Compare commits

..

14 Commits

Author SHA1 Message Date
q1anx1
3dd56195d9 fix: fix the problem of link error (#923) 2022-07-28 21:52:10 +08:00
Resulte Lee
8865244262 fix: add oauth login auto close page (#915) 2022-07-26 23:03:55 +08:00
Yixiang Zhao
3400fa1e9c feat: support local login for non-built-in users (#911)
Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>
2022-07-26 19:27:24 +08:00
Resulte Lee
bdc5c92ef0 fix: send code missing parameter & show more detail responseError (#910) 2022-07-25 23:46:38 +08:00
SLingyu
4e3eedf246 feat: fix bug that the default permission prevents admin to login in (#907)
* fix:The certs page is displayed incorrectly

* Translations for each language are added

* Replace the variables certificat with Certificat with certificate and Certificate

* Replace the variables certificat with Certificat with certificate and Certificate

* Variable names are more accurate

* Variable names are more accurate

* Modify the variable name

* fix: Default action prevents admin to login in
2022-07-24 23:36:55 +08:00
SLingyu
8e98fc5a9f feat: rename all publicKey occurrences to certificate (#894)
* fix:The certs page is displayed incorrectly

* Translations for each language are added

* Replace the variables certificat with Certificat with certificate and Certificate

* Replace the variables certificat with Certificat with certificate and Certificate

* Variable names are more accurate

* Variable names are more accurate

* Modify the variable name
2022-07-23 09:40:51 +08:00
leoshine
6f6159be07 feat: add GET method of logout API (#903) 2022-07-22 21:13:49 +08:00
Gucheng Wang
3e4dbc2dcb fix: URL bug in getUploadFileUrl function 2022-07-20 17:49:11 +08:00
Yixiang Zhao
48b5b27982 fix: invalid redirect url after sign up (#896)
* fix: invalid redirect url after sign up

Signed-off-by: Yixiang Zhao <seriouszyx@foxmail.com>

* Update App.js

* Update Setting.js

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-07-19 23:31:17 +08:00
q1anx1
1839252c30 chore(web): sort import members (#895) 2022-07-18 20:57:38 +08:00
q1anx1
1fff1db6a7 fix(web): fix the bug of infinity loop animate when unauthorized (#891)
* fix(web): fix the bug of infinity loop when unauthorized

* fix

* fix

* fix

* Update BaseListPage.js

* Update OrganizationListPage.js

* Update OrganizationListPage.js

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2022-07-17 18:20:52 +08:00
Yang Luo
a0b0e186b7 Improve i18n code and data. 2022-07-17 17:56:43 +08:00
Yang Luo
8c7f235ee1 Fix bug in uploadFile()'s URL. 2022-07-17 14:29:06 +08:00
waltcow
a0a762aa6f fix: typo in field tag in BilibiliUserInfo (#890) 2022-07-17 11:31:43 +08:00
56 changed files with 540 additions and 157 deletions

View File

@@ -78,6 +78,7 @@ p, *, *, POST, /api/get-email-and-phone, *, *
p, *, *, POST, /api/login, *, * p, *, *, POST, /api/login, *, *
p, *, *, GET, /api/get-app-login, *, * p, *, *, GET, /api/get-app-login, *, *
p, *, *, POST, /api/logout, *, * p, *, *, POST, /api/logout, *, *
p, *, *, GET, /api/logout, *, *
p, *, *, GET, /api/get-account, *, * p, *, *, GET, /api/get-account, *, *
p, *, *, GET, /api/userinfo, *, * p, *, *, GET, /api/userinfo, *, *
p, *, *, *, /api/login/oauth, *, * p, *, *, *, /api/login/oauth, *, *
@@ -92,6 +93,7 @@ p, *, *, GET, /api/get-payment, *, *
p, *, *, POST, /api/update-payment, *, * p, *, *, POST, /api/update-payment, *, *
p, *, *, POST, /api/invoice-payment, *, * p, *, *, POST, /api/invoice-payment, *, *
p, *, *, GET, /api/get-providers, *, * p, *, *, GET, /api/get-providers, *, *
p, *, *, POST, /api/notify-payment, *, *
p, *, *, POST, /api/unlink, *, * p, *, *, POST, /api/unlink, *, *
p, *, *, POST, /api/set-password, *, * p, *, *, POST, /api/set-password, *, *
p, *, *, POST, /api/send-verification-code, *, * p, *, *, POST, /api/send-verification-code, *, *

View File

@@ -228,7 +228,7 @@ func (c *ApiController) Signup() {
// @Tag Login API // @Tag Login API
// @Description logout the current user // @Description logout the current user
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /logout [post] // @router /logout [get,post]
func (c *ApiController) Logout() { func (c *ApiController) Logout() {
user := c.GetSessionUsername() user := c.GetSessionUsername()
util.LogInfo(c.Ctx, "API: [%s] logged out", user) util.LogInfo(c.Ctx, "API: [%s] logged out", user)

View File

@@ -49,8 +49,24 @@ func (c *ApiController) SendVerificationCode() {
applicationId := c.Ctx.Request.Form.Get("applicationId") applicationId := c.Ctx.Request.Form.Get("applicationId")
remoteAddr := util.GetIPFromRequest(c.Ctx.Request) remoteAddr := util.GetIPFromRequest(c.Ctx.Request)
if destType == "" || dest == "" || applicationId == "" || !strings.Contains(applicationId, "/") || checkType == "" { if destType == "" {
c.ResponseError("Missing parameter.") c.ResponseError("Missing parameter: type.")
return
}
if dest == "" {
c.ResponseError("Missing parameter: dest.")
return
}
if applicationId == "" {
c.ResponseError("Missing parameter: applicationId.")
return
}
if !strings.Contains(applicationId, "/") {
c.ResponseError("Wrong parameter: applicationId.")
return
}
if checkType == "" {
c.ResponseError("Missing parameter: checkType.")
return return
} }

View File

@@ -39,6 +39,7 @@ func readI18nFile(language string) *I18nData {
func writeI18nFile(language string, data *I18nData) { func writeI18nFile(language string, data *I18nData) {
s := util.StructToJsonFormatted(data) s := util.StructToJsonFormatted(data)
s = strings.ReplaceAll(s, "\\u0026", "&") s = strings.ReplaceAll(s, "\\u0026", "&")
s += "\n"
println(s) println(s)
util.WriteStringToPath(s, getI18nFilePath(language)) util.WriteStringToPath(s, getI18nFilePath(language))

View File

@@ -144,7 +144,7 @@ func (idp *BilibiliIdProvider) GetToken(code string) (*oauth2.Token, error) {
type BilibiliUserInfo struct { type BilibiliUserInfo struct {
Name string `json:"name"` Name string `json:"name"`
Face string `json:"face"` Face string `json:"face"`
OpenId string `json:"openid` OpenId string `json:"openid"`
} }
type BilibiliUserInfoResponse struct { type BilibiliUserInfoResponse struct {

View File

@@ -139,7 +139,7 @@
"cryptoAlgorithm": "RS256", "cryptoAlgorithm": "RS256",
"bitSize": 4096, "bitSize": 4096,
"expireInYears": 20, "expireInYears": 20,
"publicKey": "", "certificate": "",
"privateKey": "" "privateKey": ""
} }
], ],

View File

@@ -33,7 +33,7 @@ type Cert struct {
BitSize int `json:"bitSize"` BitSize int `json:"bitSize"`
ExpireInYears int `json:"expireInYears"` ExpireInYears int `json:"expireInYears"`
PublicKey string `xorm:"mediumtext" json:"publicKey"` Certificate string `xorm:"mediumtext" json:"certificate"`
PrivateKey string `xorm:"mediumtext" json:"privateKey"` PrivateKey string `xorm:"mediumtext" json:"privateKey"`
AuthorityPublicKey string `xorm:"mediumtext" json:"authorityPublicKey"` AuthorityPublicKey string `xorm:"mediumtext" json:"authorityPublicKey"`
AuthorityRootPublicKey string `xorm:"mediumtext" json:"authorityRootPublicKey"` AuthorityRootPublicKey string `xorm:"mediumtext" json:"authorityRootPublicKey"`
@@ -123,9 +123,9 @@ func UpdateCert(id string, cert *Cert) bool {
} }
func AddCert(cert *Cert) bool { func AddCert(cert *Cert) bool {
if cert.PublicKey == "" || cert.PrivateKey == "" { if cert.Certificate == "" || cert.PrivateKey == "" {
publicKey, privateKey := generateRsaKeys(cert.BitSize, cert.ExpireInYears, cert.Name, cert.Owner) certificate, privateKey := generateRsaKeys(cert.BitSize, cert.ExpireInYears, cert.Name, cert.Owner)
cert.PublicKey = publicKey cert.Certificate = certificate
cert.PrivateKey = privateKey cert.PrivateKey = privateKey
} }

View File

@@ -236,7 +236,7 @@ func CheckAccessPermission(userId string, application *Application) (bool, error
allowed := true allowed := true
var err error var err error
for _, permission := range permissions { for _, permission := range permissions {
if !permission.IsEnabled { if !permission.IsEnabled || len(permission.Users) == 0 {
continue continue
} }

View File

@@ -25,6 +25,7 @@ import (
func InitDb() { func InitDb() {
existed := initBuiltInOrganization() existed := initBuiltInOrganization()
if !existed { if !existed {
initBuiltInPermission()
initBuiltInProvider() initBuiltInProvider()
initBuiltInUser() initBuiltInUser()
initBuiltInApplication() initBuiltInApplication()
@@ -167,7 +168,7 @@ func readTokenFromFile() (string, string) {
} }
func initBuiltInCert() { func initBuiltInCert() {
tokenJwtPublicKey, tokenJwtPrivateKey := readTokenFromFile() tokenJwtCertificate, tokenJwtPrivateKey := readTokenFromFile()
cert := getCert("admin", "cert-built-in") cert := getCert("admin", "cert-built-in")
if cert != nil { if cert != nil {
return return
@@ -183,7 +184,7 @@ func initBuiltInCert() {
CryptoAlgorithm: "RS256", CryptoAlgorithm: "RS256",
BitSize: 4096, BitSize: 4096,
ExpireInYears: 20, ExpireInYears: 20,
PublicKey: tokenJwtPublicKey, Certificate: tokenJwtCertificate,
PrivateKey: tokenJwtPrivateKey, PrivateKey: tokenJwtPrivateKey,
} }
AddCert(cert) AddCert(cert)
@@ -230,3 +231,25 @@ func initBuiltInProvider() {
func initWebAuthn() { func initWebAuthn() {
gob.Register(webauthn.SessionData{}) gob.Register(webauthn.SessionData{})
} }
func initBuiltInPermission() {
permission := GetPermission("built-in/permission-built-in")
if permission != nil {
return
}
permission = &Permission{
Owner: "built-in",
Name: "permission-built-in",
CreatedTime: util.GetCurrentTime(),
DisplayName: "Built-in Permission",
Users: []string{"built-in/admin"},
Roles: []string{},
ResourceType: "Application",
Resources: []string{"app-built-in"},
Actions: []string{"Read", "Write", "Admin"},
Effect: "Allow",
IsEnabled: true,
}
AddPermission(permission)
}

View File

@@ -97,7 +97,7 @@ func GetJsonWebKeySet() (jose.JSONWebKeySet, error) {
//link here: https://self-issued.info/docs/draft-ietf-jose-json-web-key.html //link here: https://self-issued.info/docs/draft-ietf-jose-json-web-key.html
//or https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key //or https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key
for _, cert := range certs { for _, cert := range certs {
certPemBlock := []byte(cert.PublicKey) certPemBlock := []byte(cert.Certificate)
certDerBlock, _ := pem.Decode(certPemBlock) certDerBlock, _ := pem.Decode(certPemBlock)
x509Cert, _ := x509.ParseCertificate(certDerBlock.Bytes) x509Cert, _ := x509.ParseCertificate(certDerBlock.Bytes)

View File

@@ -30,7 +30,7 @@ func TestProduct(t *testing.T) {
product := GetProduct("admin/product_123") product := GetProduct("admin/product_123")
provider := getProvider(product.Owner, "provider_pay_alipay") provider := getProvider(product.Owner, "provider_pay_alipay")
cert := getCert(product.Owner, "cert-pay-alipay") cert := getCert(product.Owner, "cert-pay-alipay")
pProvider := pp.GetPaymentProvider(provider.Type, provider.ClientId, provider.ClientSecret, provider.Host, cert.PublicKey, cert.PrivateKey, cert.AuthorityPublicKey, cert.AuthorityRootPublicKey) pProvider := pp.GetPaymentProvider(provider.Type, provider.ClientId, provider.ClientSecret, provider.Host, cert.Certificate, cert.PrivateKey, cert.AuthorityPublicKey, cert.AuthorityRootPublicKey)
paymentName := util.GenerateTimeId() paymentName := util.GenerateTimeId()
returnUrl := "" returnUrl := ""

View File

@@ -214,7 +214,7 @@ func (p *Provider) getPaymentProvider() (pp.PaymentProvider, *Cert, error) {
} }
} }
pProvider := pp.GetPaymentProvider(p.Type, p.ClientId, p.ClientSecret, p.Host, cert.PublicKey, cert.PrivateKey, cert.AuthorityPublicKey, cert.AuthorityRootPublicKey) pProvider := pp.GetPaymentProvider(p.Type, p.ClientId, p.ClientSecret, p.Host, cert.Certificate, cert.PrivateKey, cert.AuthorityPublicKey, cert.AuthorityRootPublicKey)
if pProvider == nil { if pProvider == nil {
return nil, cert, fmt.Errorf("the payment provider type: %s is not supported", p.Type) return nil, cert, fmt.Errorf("the payment provider type: %s is not supported", p.Type)
} }

View File

@@ -36,7 +36,7 @@ import (
) )
//returns a saml2 response //returns a saml2 response
func NewSamlResponse(user *User, host string, publicKey string, destination string, iss string, requestId string, redirectUri []string) (*etree.Element, error) { func NewSamlResponse(user *User, host string, certificate string, destination string, iss string, requestId string, redirectUri []string) (*etree.Element, error) {
samlResponse := &etree.Element{ samlResponse := &etree.Element{
Space: "samlp", Space: "samlp",
Tag: "Response", Tag: "Response",
@@ -177,8 +177,8 @@ type Attribute struct {
func GetSamlMeta(application *Application, host string) (*IdpEntityDescriptor, error) { func GetSamlMeta(application *Application, host string) (*IdpEntityDescriptor, error) {
//_, originBackend := getOriginFromHost(host) //_, originBackend := getOriginFromHost(host)
cert := getCertByApplication(application) cert := getCertByApplication(application)
block, _ := pem.Decode([]byte(cert.PublicKey)) block, _ := pem.Decode([]byte(cert.Certificate))
publicKey := base64.StdEncoding.EncodeToString(block.Bytes) certificate := base64.StdEncoding.EncodeToString(block.Bytes)
origin := beego.AppConfig.String("origin") origin := beego.AppConfig.String("origin")
originFrontend, originBackend := getOriginFromHost(host) originFrontend, originBackend := getOriginFromHost(host)
@@ -199,7 +199,7 @@ func GetSamlMeta(application *Application, host string) (*IdpEntityDescriptor, e
KeyInfo: KeyInfo{ KeyInfo: KeyInfo{
X509Data: X509Data{ X509Data: X509Data{
X509Certificate: X509Certificate{ X509Certificate: X509Certificate{
Cert: publicKey, Cert: certificate,
}, },
}, },
}, },
@@ -248,18 +248,18 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
return "", "", fmt.Errorf("err: invalid issuer url") return "", "", fmt.Errorf("err: invalid issuer url")
} }
// get public key string // get certificate string
cert := getCertByApplication(application) cert := getCertByApplication(application)
block, _ := pem.Decode([]byte(cert.PublicKey)) block, _ := pem.Decode([]byte(cert.Certificate))
publicKey := base64.StdEncoding.EncodeToString(block.Bytes) certificate := base64.StdEncoding.EncodeToString(block.Bytes)
_, originBackend := getOriginFromHost(host) _, originBackend := getOriginFromHost(host)
// build signedResponse // build signedResponse
samlResponse, _ := NewSamlResponse(user, originBackend, publicKey, authnRequest.AssertionConsumerServiceURL, authnRequest.Issuer.Url, authnRequest.ID, application.RedirectUris) samlResponse, _ := NewSamlResponse(user, originBackend, certificate, authnRequest.AssertionConsumerServiceURL, authnRequest.Issuer.Url, authnRequest.ID, application.RedirectUris)
randomKeyStore := &X509Key{ randomKeyStore := &X509Key{
PrivateKey: cert.PrivateKey, PrivateKey: cert.PrivateKey,
X509Certificate: publicKey, X509Certificate: certificate,
} }
ctx := dsig.NewDefaultSigningContext(randomKeyStore) ctx := dsig.NewDefaultSigningContext(randomKeyStore)
ctx.Hash = crypto.SHA1 ctx.Hash = crypto.SHA1

View File

@@ -72,9 +72,9 @@ func getUploadFileUrl(provider *Provider, fullFilePath string, hasTimestamp bool
host = fmt.Sprintf("%s/%s", host, provider.Bucket) host = fmt.Sprintf("%s/%s", host, provider.Bucket)
} }
fileUrl := util.UrlJoin(host, objectKey) fileUrl := util.UrlJoin(host, escapePath(objectKey))
if hasTimestamp { if hasTimestamp {
fileUrl = fmt.Sprintf("%s?t=%s", util.UrlJoin(host, objectKey), util.GetCurrentUnixTime()) fileUrl = fmt.Sprintf("%s?t=%s", fileUrl, util.GetCurrentUnixTime())
} }
return fileUrl, objectKey return fileUrl, objectKey

View File

@@ -241,11 +241,11 @@ func GetValidationBySaml(samlRequest string, host string) (string, string, error
samlResponse := NewSamlResponse11(user, request.RequestID, host) samlResponse := NewSamlResponse11(user, request.RequestID, host)
cert := getCertByApplication(application) cert := getCertByApplication(application)
block, _ := pem.Decode([]byte(cert.PublicKey)) block, _ := pem.Decode([]byte(cert.Certificate))
publicKey := base64.StdEncoding.EncodeToString(block.Bytes) certificate := base64.StdEncoding.EncodeToString(block.Bytes)
randomKeyStore := &X509Key{ randomKeyStore := &X509Key{
PrivateKey: cert.PrivateKey, PrivateKey: cert.PrivateKey,
X509Certificate: publicKey, X509Certificate: certificate,
} }
ctx := dsig.NewDefaultSigningContext(randomKeyStore) ctx := dsig.NewDefaultSigningContext(randomKeyStore)

View File

@@ -129,13 +129,13 @@ func ParseJwtToken(token string, cert *Cert) (*Claims, error) {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
} }
// RSA public key // RSA certificate
publicKey, err := jwt.ParseRSAPublicKeyFromPEM([]byte(cert.PublicKey)) certificate, err := jwt.ParseRSAPublicKeyFromPEM([]byte(cert.Certificate))
if err != nil { if err != nil {
return nil, err return nil, err
} }
return publicKey, nil return certificate, nil
}) })
if t != nil { if t != nil {

View File

@@ -23,10 +23,10 @@ import (
func TestGenerateRsaKeys(t *testing.T) { func TestGenerateRsaKeys(t *testing.T) {
fileId := "token_jwt_key" fileId := "token_jwt_key"
publicKey, privateKey := generateRsaKeys(4096, 20, "Casdoor Cert", "Casdoor Organization") certificate, privateKey := generateRsaKeys(4096, 20, "Casdoor Cert", "Casdoor Organization")
// Write certificate (aka public key) to file. // Write certificate (aka certificate) to file.
util.WriteStringToPath(publicKey, fmt.Sprintf("%s.pem", fileId)) util.WriteStringToPath(certificate, fmt.Sprintf("%s.pem", fileId))
// Write private key to file. // Write private key to file.
util.WriteStringToPath(privateKey, fmt.Sprintf("%s.key", fileId)) util.WriteStringToPath(privateKey, fmt.Sprintf("%s.key", fileId))

View File

@@ -106,6 +106,10 @@ func setUserProperty(user *User, field string, value string) {
if value == "" { if value == "" {
delete(user.Properties, field) delete(user.Properties, field)
} else { } else {
if user.Properties == nil {
user.Properties = make(map[string]string)
}
user.Properties[field] = value user.Properties[field] = value
} }
} }

View File

@@ -28,7 +28,7 @@ type AlipayPaymentProvider struct {
Client *alipay.Client Client *alipay.Client
} }
func NewAlipayPaymentProvider(appId string, appPublicKey string, appPrivateKey string, authorityPublicKey string, authorityRootPublicKey string) *AlipayPaymentProvider { func NewAlipayPaymentProvider(appId string, appCertificate string, appPrivateKey string, authorityPublicKey string, authorityRootPublicKey string) *AlipayPaymentProvider {
pp := &AlipayPaymentProvider{} pp := &AlipayPaymentProvider{}
client, err := alipay.NewClient(appId, appPrivateKey, true) client, err := alipay.NewClient(appId, appPrivateKey, true)
@@ -36,7 +36,7 @@ func NewAlipayPaymentProvider(appId string, appPublicKey string, appPrivateKey s
panic(err) panic(err)
} }
err = client.SetCertSnByContent([]byte(appPublicKey), []byte(authorityRootPublicKey), []byte(authorityPublicKey)) err = client.SetCertSnByContent([]byte(appCertificate), []byte(authorityRootPublicKey), []byte(authorityPublicKey))
if err != nil { if err != nil {
panic(err) panic(err)
} }

View File

@@ -22,9 +22,9 @@ type PaymentProvider interface {
GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error)
} }
func GetPaymentProvider(typ string, appId string, clientSecret string, host string, appPublicKey string, appPrivateKey string, authorityPublicKey string, authorityRootPublicKey string) PaymentProvider { func GetPaymentProvider(typ string, appId string, clientSecret string, host string, appCertificate string, appPrivateKey string, authorityPublicKey string, authorityRootPublicKey string) PaymentProvider {
if typ == "Alipay" { if typ == "Alipay" {
return NewAlipayPaymentProvider(appId, appPublicKey, appPrivateKey, authorityPublicKey, authorityRootPublicKey) return NewAlipayPaymentProvider(appId, appCertificate, appPrivateKey, authorityPublicKey, authorityRootPublicKey)
} else if typ == "GC" { } else if typ == "GC" {
return NewGcPaymentProvider(appId, clientSecret, host) return NewGcPaymentProvider(appId, clientSecret, host)
} }

View File

@@ -122,6 +122,10 @@ func AuthzFilter(ctx *context.Context) {
urlPath := getUrlPath(ctx.Request.URL.Path) urlPath := getUrlPath(ctx.Request.URL.Path)
objOwner, objName := getObject(ctx) objOwner, objName := getObject(ctx)
if strings.HasPrefix(urlPath, "/api/notify-payment") {
urlPath = "/api/notify-payment"
}
isAllowed := authz.IsAllowed(subOwner, subName, method, urlPath, objOwner, objName) isAllowed := authz.IsAllowed(subOwner, subName, method, urlPath, objOwner, objName)
result := "deny" result := "deny"

View File

@@ -48,7 +48,7 @@ func initAPI() {
beego.Router("/api/signup", &controllers.ApiController{}, "POST:Signup") beego.Router("/api/signup", &controllers.ApiController{}, "POST:Signup")
beego.Router("/api/login", &controllers.ApiController{}, "POST:Login") beego.Router("/api/login", &controllers.ApiController{}, "POST:Login")
beego.Router("/api/get-app-login", &controllers.ApiController{}, "GET:GetApplicationLogin") beego.Router("/api/get-app-login", &controllers.ApiController{}, "GET:GetApplicationLogin")
beego.Router("/api/logout", &controllers.ApiController{}, "POST:Logout") beego.Router("/api/logout", &controllers.ApiController{}, "GET,POST:Logout")
beego.Router("/api/get-account", &controllers.ApiController{}, "GET:GetAccount") beego.Router("/api/get-account", &controllers.ApiController{}, "GET:GetAccount")
beego.Router("/api/userinfo", &controllers.ApiController{}, "GET:GetUserinfo") beego.Router("/api/userinfo", &controllers.ApiController{}, "GET:GetUserinfo")
beego.Router("/api/unlink", &controllers.ApiController{}, "POST:Unlink") beego.Router("/api/unlink", &controllers.ApiController{}, "POST:Unlink")

View File

@@ -2418,6 +2418,21 @@
} }
}, },
"/api/logout": { "/api/logout": {
"get": {
"tags": [
"Login API"
],
"description": "logout the current user",
"operationId": "ApiController.Logout",
"responses": {
"200": {
"description": "The Response object",
"schema": {
"$ref": "#/definitions/controllers.Response"
}
}
}
},
"post": { "post": {
"tags": [ "tags": [
"Login API" "Login API"
@@ -3096,14 +3111,120 @@
], ],
"operationId": "ApiController.VerifyCaptcha" "operationId": "ApiController.VerifyCaptcha"
} }
},
"/api/webauthn/signin/begin": {
"get": {
"tags": [
"Login API"
],
"description": "WebAuthn Login Flow 1st stage",
"operationId": "ApiController.WebAuthnSigninBegin",
"parameters": [
{
"in": "query",
"name": "owner",
"description": "owner",
"required": true,
"type": "string"
},
{
"in": "query",
"name": "name",
"description": "name",
"required": true,
"type": "string"
}
],
"responses": {
"200": {
"description": "The CredentialAssertion object",
"schema": {
"$ref": "#/definitions/protocol.CredentialAssertion"
}
}
}
}
},
"/api/webauthn/signin/finish": {
"post": {
"tags": [
"Login API"
],
"description": "WebAuthn Login Flow 2nd stage",
"operationId": "ApiController.WebAuthnSigninBegin",
"parameters": [
{
"in": "body",
"name": "body",
"description": "authenticator assertion Response",
"required": true,
"schema": {
"$ref": "#/definitions/protocol.CredentialAssertionResponse"
}
}
],
"responses": {
"200": {
"description": "\"The Response object\"",
"schema": {
"$ref": "#/definitions/Response"
}
}
}
}
},
"/api/webauthn/signup/begin": {
"get": {
"tags": [
"User API"
],
"description": "WebAuthn Registration Flow 1st stage",
"operationId": "ApiController.WebAuthnSignupBegin",
"responses": {
"200": {
"description": "The CredentialCreationOptions object",
"schema": {
"$ref": "#/definitions/protocol.CredentialCreation"
}
}
}
}
},
"/api/webauthn/signup/finish": {
"post": {
"tags": [
"User API"
],
"description": "WebAuthn Registration Flow 2nd stage",
"operationId": "ApiController.WebAuthnSignupFinish",
"parameters": [
{
"in": "body",
"name": "body",
"description": "authenticator attestation Response",
"required": true,
"schema": {
"$ref": "#/definitions/protocol.CredentialCreationResponse"
}
}
],
"responses": {
"200": {
"description": "\"The Response object\"",
"schema": {
"$ref": "#/definitions/Response"
}
}
}
}
} }
}, },
"definitions": { "definitions": {
"2127.0xc000398090.false": { "2127.0xc000427560.false": {
"title": "false", "title": "false",
"type": "object" "type": "object"
}, },
"2161.0xc0003980c0.false": { "2161.0xc000427590.false": {
"title": "false", "title": "false",
"type": "object" "type": "object"
}, },
@@ -3221,10 +3342,10 @@
"type": "object", "type": "object",
"properties": { "properties": {
"data": { "data": {
"$ref": "#/definitions/2127.0xc000398090.false" "$ref": "#/definitions/2127.0xc000427560.false"
}, },
"data2": { "data2": {
"$ref": "#/definitions/2161.0xc0003980c0.false" "$ref": "#/definitions/2161.0xc000427590.false"
}, },
"msg": { "msg": {
"type": "string" "type": "string"
@@ -3329,12 +3450,18 @@
"enablePassword": { "enablePassword": {
"type": "boolean" "type": "boolean"
}, },
"enableSamlCompress": {
"type": "boolean"
},
"enableSignUp": { "enableSignUp": {
"type": "boolean" "type": "boolean"
}, },
"enableSigninSession": { "enableSigninSession": {
"type": "boolean" "type": "boolean"
}, },
"enableWebAuthn": {
"type": "boolean"
},
"expireInHours": { "expireInHours": {
"type": "integer", "type": "integer",
"format": "int64" "format": "int64"
@@ -3444,7 +3571,7 @@
"privateKey": { "privateKey": {
"type": "string" "type": "string"
}, },
"publicKey": { "certificate": {
"type": "string" "type": "string"
}, },
"scope": { "scope": {
@@ -4507,6 +4634,12 @@
"updatedTime": { "updatedTime": {
"type": "string" "type": "string"
}, },
"webauthnCredentials": {
"type": "array",
"items": {
"$ref": "#/definitions/webauthn.Credential"
}
},
"wechat": { "wechat": {
"type": "string" "type": "string"
}, },
@@ -4596,6 +4729,26 @@
} }
} }
}, },
"protocol.CredentialAssertion": {
"title": "CredentialAssertion",
"type": "object"
},
"protocol.CredentialAssertionResponse": {
"title": "CredentialAssertionResponse",
"type": "object"
},
"protocol.CredentialCreation": {
"title": "CredentialCreation",
"type": "object"
},
"protocol.CredentialCreationResponse": {
"title": "CredentialCreationResponse",
"type": "object"
},
"webauthn.Credential": {
"title": "Credential",
"type": "object"
},
"xorm.Engine": { "xorm.Engine": {
"title": "Engine", "title": "Engine",
"type": "object" "type": "object"

View File

@@ -1584,6 +1584,16 @@ paths:
schema: schema:
$ref: '#/definitions/object.TokenError' $ref: '#/definitions/object.TokenError'
/api/logout: /api/logout:
get:
tags:
- Login API
description: logout the current user
operationId: ApiController.Logout
responses:
"200":
description: The Response object
schema:
$ref: '#/definitions/controllers.Response'
post: post:
tags: tags:
- Login API - Login API
@@ -2028,11 +2038,80 @@ paths:
tags: tags:
- Verification API - Verification API
operationId: ApiController.VerifyCaptcha operationId: ApiController.VerifyCaptcha
/api/webauthn/signin/begin:
get:
tags:
- Login API
description: WebAuthn Login Flow 1st stage
operationId: ApiController.WebAuthnSigninBegin
parameters:
- in: query
name: owner
description: owner
required: true
type: string
- in: query
name: name
description: name
required: true
type: string
responses:
"200":
description: The CredentialAssertion object
schema:
$ref: '#/definitions/protocol.CredentialAssertion'
/api/webauthn/signin/finish:
post:
tags:
- Login API
description: WebAuthn Login Flow 2nd stage
operationId: ApiController.WebAuthnSigninBegin
parameters:
- in: body
name: body
description: authenticator assertion Response
required: true
schema:
$ref: '#/definitions/protocol.CredentialAssertionResponse'
responses:
"200":
description: '"The Response object"'
schema:
$ref: '#/definitions/Response'
/api/webauthn/signup/begin:
get:
tags:
- User API
description: WebAuthn Registration Flow 1st stage
operationId: ApiController.WebAuthnSignupBegin
responses:
"200":
description: The CredentialCreationOptions object
schema:
$ref: '#/definitions/protocol.CredentialCreation'
/api/webauthn/signup/finish:
post:
tags:
- User API
description: WebAuthn Registration Flow 2nd stage
operationId: ApiController.WebAuthnSignupFinish
parameters:
- in: body
name: body
description: authenticator attestation Response
required: true
schema:
$ref: '#/definitions/protocol.CredentialCreationResponse'
responses:
"200":
description: '"The Response object"'
schema:
$ref: '#/definitions/Response'
definitions: definitions:
2127.0xc000398090.false: 2127.0xc000427560.false:
title: "false" title: "false"
type: object type: object
2161.0xc0003980c0.false: 2161.0xc000427590.false:
title: "false" title: "false"
type: object type: object
Response: Response:
@@ -2113,9 +2192,9 @@ definitions:
type: object type: object
properties: properties:
data: data:
$ref: '#/definitions/2127.0xc000398090.false' $ref: '#/definitions/2127.0xc000427560.false'
data2: data2:
$ref: '#/definitions/2161.0xc0003980c0.false' $ref: '#/definitions/2161.0xc000427590.false'
msg: msg:
type: string type: string
name: name:
@@ -2185,10 +2264,14 @@ definitions:
type: boolean type: boolean
enablePassword: enablePassword:
type: boolean type: boolean
enableSamlCompress:
type: boolean
enableSignUp: enableSignUp:
type: boolean type: boolean
enableSigninSession: enableSigninSession:
type: boolean type: boolean
enableWebAuthn:
type: boolean
expireInHours: expireInHours:
type: integer type: integer
format: int64 format: int64
@@ -2263,7 +2346,7 @@ definitions:
type: string type: string
privateKey: privateKey:
type: string type: string
publicKey: certificate:
type: string type: string
scope: scope:
type: string type: string
@@ -2977,6 +3060,10 @@ definitions:
type: string type: string
updatedTime: updatedTime:
type: string type: string
webauthnCredentials:
type: array
items:
$ref: '#/definitions/webauthn.Credential'
wechat: wechat:
type: string type: string
wecom: wecom:
@@ -3035,6 +3122,21 @@ definitions:
type: string type: string
url: url:
type: string type: string
protocol.CredentialAssertion:
title: CredentialAssertion
type: object
protocol.CredentialAssertionResponse:
title: CredentialAssertionResponse
type: object
protocol.CredentialCreation:
title: CredentialCreation
type: object
protocol.CredentialCreationResponse:
title: CredentialCreationResponse
type: object
webauthn.Credential:
title: Credential
type: object
xorm.Engine: xorm.Engine:
title: Engine title: Engine
type: object type: object

View File

@@ -45,6 +45,10 @@
"curly": ["error", "all"], "curly": ["error", "all"],
"brace-style": ["error", "1tbs", { "allowSingleLine": true }], "brace-style": ["error", "1tbs", { "allowSingleLine": true }],
"no-mixed-spaces-and-tabs": "error", "no-mixed-spaces-and-tabs": "error",
"sort-imports": ["error", {
"ignoreDeclarationSort": true
}],
"react/prop-types": "off", "react/prop-types": "off",
"react/display-name": "off", "react/display-name": "off",

View File

@@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
import React from "react"; import React from "react";
import {DownOutlined, DeleteOutlined, UpOutlined} from "@ant-design/icons"; import {DeleteOutlined, DownOutlined, UpOutlined} from "@ant-design/icons";
import {Button, Col, Row, Select, Switch, Table, Tooltip} from "antd"; import {Button, Col, Row, Select, Switch, Table, Tooltip} from "antd";
import * as Setting from "./Setting"; import * as Setting from "./Setting";
import i18next from "i18next"; import i18next from "i18next";

View File

@@ -17,7 +17,7 @@ import "./App.less";
import {Helmet} from "react-helmet"; import {Helmet} from "react-helmet";
import * as Setting from "./Setting"; import * as Setting from "./Setting";
import {DownOutlined, LogoutOutlined, SettingOutlined} from "@ant-design/icons"; import {DownOutlined, LogoutOutlined, SettingOutlined} from "@ant-design/icons";
import {Avatar, BackTop, Dropdown, Layout, Menu, Card, Result, Button} from "antd"; import {Avatar, BackTop, Button, Card, Dropdown, Layout, Menu, Result} from "antd";
import {Link, Redirect, Route, Switch, withRouter} from "react-router-dom"; import {Link, Redirect, Route, Switch, withRouter} from "react-router-dom";
import OrganizationListPage from "./OrganizationListPage"; import OrganizationListPage from "./OrganizationListPage";
import OrganizationEditPage from "./OrganizationEditPage"; import OrganizationEditPage from "./OrganizationEditPage";
@@ -235,6 +235,8 @@ class App extends Component {
AuthBackend.logout() AuthBackend.logout()
.then((res) => { .then((res) => {
if (res.status === "ok") { if (res.status === "ok") {
const owner = this.state.account.owner;
this.setState({ this.setState({
account: null account: null
}); });
@@ -243,7 +245,9 @@ class App extends Component {
let redirectUri = res.data2; let redirectUri = res.data2;
if (redirectUri !== null && redirectUri !== undefined && redirectUri !== "") { if (redirectUri !== null && redirectUri !== undefined && redirectUri !== "") {
Setting.goToLink(redirectUri); Setting.goToLink(redirectUri);
}else{ } else if (owner !== "built-in") {
Setting.goToLink(`${window.location.origin}/login/${owner}`);
} else {
Setting.goToLinkSoft(this, "/"); Setting.goToLinkSoft(this, "/");
} }
} else { } else {
@@ -669,7 +673,9 @@ class App extends Component {
<Route exact path="/signup" render={(props) => this.renderHomeIfLoggedIn(<SignupPage account={this.state.account} {...props} />)} /> <Route exact path="/signup" render={(props) => this.renderHomeIfLoggedIn(<SignupPage account={this.state.account} {...props} />)} />
<Route exact path="/signup/:applicationName" render={(props) => this.renderHomeIfLoggedIn(<SignupPage account={this.state.account} {...props} onUpdateAccount={(account) => {this.onUpdateAccount(account);}} />)} /> <Route exact path="/signup/:applicationName" render={(props) => this.renderHomeIfLoggedIn(<SignupPage account={this.state.account} {...props} onUpdateAccount={(account) => {this.onUpdateAccount(account);}} />)} />
<Route exact path="/login" render={(props) => this.renderHomeIfLoggedIn(<SelfLoginPage account={this.state.account} {...props} />)} /> <Route exact path="/login" render={(props) => this.renderHomeIfLoggedIn(<SelfLoginPage account={this.state.account} {...props} />)} />
<Route exact path="/signup/oauth/authorize" render={(props) => <LoginPage account={this.state.account} type={"code"} mode={"signup"} {...props} onUpdateAccount={(account) => {this.onUpdateAccount(account);}} />} /> <Route exact path="/login/:owner" render={(props) => this.renderHomeIfLoggedIn(<SelfLoginPage account={this.state.account} {...props} />)} />
<Route exact path="/auto-signup/oauth/authorize" render={(props) => <LoginPage account={this.state.account} type={"code"} mode={"signup"} {...props} onUpdateAccount={(account) => {this.onUpdateAccount(account);}} />} />
<Route exact path="/signup/oauth/authorize" render={(props) => <SignupPage account={this.state.account} {...props} onUpdateAccount={(account) => {this.onUpdateAccount(account);}} />} />
<Route exact path="/login/oauth/authorize" render={(props) => <LoginPage account={this.state.account} type={"code"} mode={"signin"} {...props} onUpdateAccount={(account) => {this.onUpdateAccount(account);}} />} /> <Route exact path="/login/oauth/authorize" render={(props) => <LoginPage account={this.state.account} type={"code"} mode={"signin"} {...props} onUpdateAccount={(account) => {this.onUpdateAccount(account);}} />} />
<Route exact path="/login/saml/authorize/:owner/:applicationName" render={(props) => <LoginPage account={this.state.account} type={"saml"} mode={"signin"} {...props} onUpdateAccount={(account) => {this.onUpdateAccount(account);}} />} /> <Route exact path="/login/saml/authorize/:owner/:applicationName" render={(props) => <LoginPage account={this.state.account} type={"saml"} mode={"signin"} {...props} onUpdateAccount={(account) => {this.onUpdateAccount(account);}} />} />
<Route exact path="/cas/:owner/:casApplicationName/logout" render={(props) => this.renderHomeIfLoggedIn(<CasLogout clearAccount={() => this.setState({account: null})} {...props} />)} /> <Route exact path="/cas/:owner/:casApplicationName/logout" render={(props) => this.renderHomeIfLoggedIn(<CasLogout clearAccount={() => this.setState({account: null})} {...props} />)} />

View File

@@ -30,6 +30,7 @@ class BaseListPage extends React.Component {
loading: false, loading: false,
searchText: "", searchText: "",
searchedColumn: "", searchedColumn: "",
isAuthorized: true,
}; };
} }

View File

@@ -164,25 +164,25 @@ class CertEditPage extends React.Component {
</Row> </Row>
<Row style={{marginTop: "20px"}} > <Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}> <Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("cert:Public key"), i18next.t("cert:Public key - Tooltip"))} : {Setting.getLabel(i18next.t("cert:Certificate"), i18next.t("cert:Certificate - Tooltip"))} :
</Col> </Col>
<Col span={9} > <Col span={9} >
<Button style={{marginRight: "10px", marginBottom: "10px"}} onClick={() => { <Button style={{marginRight: "10px", marginBottom: "10px"}} onClick={() => {
copy(this.state.cert.publicKey); copy(this.state.cert.certificate);
Setting.showMessage("success", i18next.t("cert:Public key copied to clipboard successfully")); Setting.showMessage("success", i18next.t("cert:Certificate copied to clipboard successfully"));
}} }}
> >
{i18next.t("cert:Copy public key")} {i18next.t("cert:Copy certificate")}
</Button> </Button>
<Button type="primary" onClick={() => { <Button type="primary" onClick={() => {
const blob = new Blob([this.state.cert.publicKey], {type: "text/plain;charset=utf-8"}); const blob = new Blob([this.state.cert.certificate], {type: "text/plain;charset=utf-8"});
FileSaver.saveAs(blob, "token_jwt_key.pem"); FileSaver.saveAs(blob, "token_jwt_key.pem");
}} }}
> >
{i18next.t("cert:Download public key")} {i18next.t("cert:Download certificate")}
</Button> </Button>
<TextArea autoSize={{minRows: 30, maxRows: 30}} value={this.state.cert.publicKey} onChange={e => { <TextArea autoSize={{minRows: 30, maxRows: 30}} value={this.state.cert.certificate} onChange={e => {
this.updateCertField("publicKey", e.target.value); this.updateCertField("certificate", e.target.value);
}} /> }} />
</Col> </Col>
<Col span={1} /> <Col span={1} />

View File

@@ -34,7 +34,7 @@ class CertListPage extends BaseListPage {
cryptoAlgorithm: "RS256", cryptoAlgorithm: "RS256",
bitSize: 4096, bitSize: 4096,
expireInYears: 20, expireInYears: 20,
publicKey: "", certificate: "",
privateKey: "", privateKey: "",
}; };
} }

View File

@@ -16,7 +16,7 @@ import React, {useState} from "react";
import Cropper from "react-cropper"; import Cropper from "react-cropper";
import "cropperjs/dist/cropper.css"; import "cropperjs/dist/cropper.css";
import * as Setting from "./Setting"; import * as Setting from "./Setting";
import {Button, Row, Col, Modal} from "antd"; import {Button, Col, Modal, Row} from "antd";
import i18next from "i18next"; import i18next from "i18next";
import * as ResourceBackend from "./backend/ResourceBackend"; import * as ResourceBackend from "./backend/ResourceBackend";

View File

@@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
import React from "react"; import React from "react";
import {Button, Col, Row, Table, Popconfirm} from "antd"; import {Button, Col, Popconfirm, Row, Table} from "antd";
import * as Setting from "./Setting"; import * as Setting from "./Setting";
import * as LdapBackend from "./backend/LdapBackend"; import * as LdapBackend from "./backend/LdapBackend";
import i18next from "i18next"; import i18next from "i18next";

View File

@@ -14,7 +14,7 @@
import React from "react"; import React from "react";
import {Link} from "react-router-dom"; import {Link} from "react-router-dom";
import {Button, Popconfirm, Switch, Table} from "antd"; import {Button, Popconfirm, Result, Switch, Table} from "antd";
import moment from "moment"; import moment from "moment";
import * as Setting from "./Setting"; import * as Setting from "./Setting";
import * as OrganizationBackend from "./backend/OrganizationBackend"; import * as OrganizationBackend from "./backend/OrganizationBackend";
@@ -235,6 +235,17 @@ class OrganizationListPage extends BaseListPage {
showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total), showTotal: () => i18next.t("general:{total} in total").replace("{total}", this.state.pagination.total),
}; };
if (!this.state.isAuthorized) {
return (
<Result
status="403"
title="403 Unauthorized"
subTitle={i18next.t("general:Sorry, you do not have permission to access this page.")}
extra={<a href="/"><Button type="primary">{i18next.t("general:Back Home")}</Button></a>}
/>
);
}
return ( return (
<div> <div>
<Table scroll={{x: "max-content"}} columns={columns} dataSource={organizations} rowKey="name" size="middle" bordered pagination={paginationProps} <Table scroll={{x: "max-content"}} columns={columns} dataSource={organizations} rowKey="name" size="middle" bordered pagination={paginationProps}
@@ -272,6 +283,13 @@ class OrganizationListPage extends BaseListPage {
searchText: params.searchText, searchText: params.searchText,
searchedColumn: params.searchedColumn, searchedColumn: params.searchedColumn,
}); });
} else {
if (res.msg.includes("Unauthorized")) {
this.setState({
loading: false,
isAuthorized: false,
});
}
} }
}); });
}; };

View File

@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import {Button, Col, Modal, Row, Input} from "antd"; import {Button, Col, Input, Modal, Row} from "antd";
import i18next from "i18next"; import i18next from "i18next";
import React from "react"; import React from "react";
import * as UserBackend from "./backend/UserBackend"; import * as UserBackend from "./backend/UserBackend";

View File

@@ -622,7 +622,7 @@ class ProviderEditPage extends React.Component {
</Row> </Row>
<Row style={{marginTop: "20px"}} > <Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}> <Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("provider:IdP"), i18next.t("provider:IdP public key"))} : {Setting.getLabel(i18next.t("provider:IdP"), i18next.t("provider:IdP certificate"))} :
</Col> </Col>
<Col span={22} > <Col span={22} >
<Input value={this.state.provider.idP} onChange={e => { <Input value={this.state.provider.idP} onChange={e => {

View File

@@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
import React from "react"; import React from "react";
import {DownOutlined, DeleteOutlined, UpOutlined} from "@ant-design/icons"; import {DeleteOutlined, DownOutlined, UpOutlined} from "@ant-design/icons";
import {Button, Col, Row, Select, Switch, Table, Tooltip} from "antd"; import {Button, Col, Row, Select, Switch, Table, Tooltip} from "antd";
import * as Setting from "./Setting"; import * as Setting from "./Setting";
import i18next from "i18next"; import i18next from "i18next";

View File

@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import {Button, Col, Modal, Row, Input} from "antd"; import {Button, Col, Input, Modal, Row} from "antd";
import i18next from "i18next"; import i18next from "i18next";
import React from "react"; import React from "react";
import * as Setting from "./Setting"; import * as Setting from "./Setting";

View File

@@ -14,7 +14,7 @@
import React from "react"; import React from "react";
import * as Setting from "./Setting"; import * as Setting from "./Setting";
import {Menu, Dropdown} from "antd"; import {Dropdown, Menu} from "antd";
import {createFromIconfontCN} from "@ant-design/icons"; import {createFromIconfontCN} from "@ant-design/icons";
import "./App.less"; import "./App.less";

View File

@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
import {message, Tag, Tooltip} from "antd"; import {Tag, Tooltip, message} from "antd";
import {QuestionCircleTwoTone} from "@ant-design/icons"; import {QuestionCircleTwoTone} from "@ant-design/icons";
import React from "react"; import React from "react";
import {isMobile as isMobileDevice} from "react-device-detect"; import {isMobile as isMobileDevice} from "react-device-detect";
@@ -662,8 +662,8 @@ export function goToLogin(ths, application) {
return; return;
} }
if (!application.enablePassword && window.location.pathname.includes("/signup/oauth/authorize")) { if (!application.enablePassword && window.location.pathname.includes("/auto-signup/oauth/authorize")) {
const link = window.location.href.replace("/signup/oauth/authorize", "/login/oauth/authorize"); const link = window.location.href.replace("/auto-signup/oauth/authorize", "/login/oauth/authorize");
goToLink(link); goToLink(link);
return; return;
} }
@@ -685,7 +685,7 @@ export function goToSignup(ths, application) {
} }
if (!application.enablePassword && window.location.pathname.includes("/login/oauth/authorize")) { if (!application.enablePassword && window.location.pathname.includes("/login/oauth/authorize")) {
const link = window.location.href.replace("/login/oauth/authorize", "/signup/oauth/authorize"); const link = window.location.href.replace("/login/oauth/authorize", "/auto-signup/oauth/authorize");
goToLink(link); goToLink(link);
return; return;
} }

View File

@@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
import React from "react"; import React from "react";
import {DownOutlined, DeleteOutlined, UpOutlined} from "@ant-design/icons"; import {DeleteOutlined, DownOutlined, UpOutlined} from "@ant-design/icons";
import {Button, Col, Row, Select, Switch, Table, Tooltip} from "antd"; import {Button, Col, Row, Select, Switch, Table, Tooltip} from "antd";
import * as Setting from "./Setting"; import * as Setting from "./Setting";
import i18next from "i18next"; import i18next from "i18next";

View File

@@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
import React from "react"; import React from "react";
import {DownOutlined, DeleteOutlined, UpOutlined} from "@ant-design/icons"; import {DeleteOutlined, DownOutlined, UpOutlined} from "@ant-design/icons";
import {Button, Col, Input, Row, Select, Switch, Table, Tooltip} from "antd"; import {Button, Col, Input, Row, Select, Switch, Table, Tooltip} from "antd";
import * as Setting from "./Setting"; import * as Setting from "./Setting";
import i18next from "i18next"; import i18next from "i18next";

View File

@@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
import React from "react"; import React from "react";
import {DownOutlined, DeleteOutlined, UpOutlined, LinkOutlined} from "@ant-design/icons"; import {DeleteOutlined, DownOutlined, LinkOutlined, UpOutlined} from "@ant-design/icons";
import {Button, Col, Input, Row, Table, Tooltip} from "antd"; import {Button, Col, Input, Row, Table, Tooltip} from "antd";
import * as Setting from "./Setting"; import * as Setting from "./Setting";
import i18next from "i18next"; import i18next from "i18next";

View File

@@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
import React from "react"; import React from "react";
import {DownOutlined, DeleteOutlined, UpOutlined} from "@ant-design/icons"; import {DeleteOutlined, DownOutlined, UpOutlined} from "@ant-design/icons";
import {Button, Col, Input, Row, Table, Tooltip} from "antd"; import {Button, Col, Input, Row, Table, Tooltip} from "antd";
import * as Setting from "./Setting"; import * as Setting from "./Setting";
import i18next from "i18next"; import i18next from "i18next";

View File

@@ -62,7 +62,7 @@ class ForgetPage extends React.Component {
} else { } else {
Util.showMessage( Util.showMessage(
"error", "error",
i18next.t("forget:Unknown forgot type: ") + this.state.type i18next.t("forget:Unknown forget type: ") + this.state.type
); );
} }
} }

View File

@@ -191,6 +191,10 @@ class LoginPage extends React.Component {
values["type"] = "saml"; values["type"] = "saml";
} }
if (this.state.owner != null) {
values["organization"] = this.state.owner;
}
AuthBackend.login(values, oAuthParams) AuthBackend.login(values, oAuthParams)
.then((res) => { .then((res) => {
if (res.status === "ok") { if (res.status === "ok") {
@@ -203,6 +207,7 @@ class LoginPage extends React.Component {
} else if (responseType === "code") { } else if (responseType === "code") {
const code = res.data; const code = res.data;
const concatChar = oAuthParams?.redirectUri?.includes("?") ? "&" : "?"; const concatChar = oAuthParams?.redirectUri?.includes("?") ? "&" : "?";
const noRedirect = oAuthParams.noRedirect;
if (Setting.hasPromptPage(application)) { if (Setting.hasPromptPage(application)) {
AuthBackend.getAccount("") AuthBackend.getAccount("")
@@ -224,7 +229,19 @@ class LoginPage extends React.Component {
} }
}); });
} else { } else {
Setting.goToLink(`${oAuthParams.redirectUri}${concatChar}code=${code}&state=${oAuthParams.state}`); if (noRedirect === "true") {
window.close();
const newWindow = window.open(`${oAuthParams.redirectUri}${concatChar}code=${code}&state=${oAuthParams.state}`);
if (newWindow) {
setInterval(() => {
if (!newWindow.closed) {
newWindow.close();
}
}, 1000);
}
} else {
Setting.goToLink(`${oAuthParams.redirectUri}${concatChar}code=${code}&state=${oAuthParams.state}`);
}
} }
// Util.showMessage("success", `Authorization code: ${res.data}`); // Util.showMessage("success", `Authorization code: ${res.data}`);
@@ -638,13 +655,13 @@ class LoginPage extends React.Component {
throw credentialRequestOptions.status.msg; throw credentialRequestOptions.status.msg;
} }
credentialRequestOptions.publicKey.challenge = UserWebauthnBackend.webAuthnBufferDecode(credentialRequestOptions.publicKey.challenge); credentialRequestOptions.certificate.challenge = UserWebauthnBackend.webAuthnBufferDecode(credentialRequestOptions.certificate.challenge);
credentialRequestOptions.publicKey.allowCredentials.forEach(function(listItem) { credentialRequestOptions.certificate.allowCredentials.forEach(function(listItem) {
listItem.id = UserWebauthnBackend.webAuthnBufferDecode(listItem.id); listItem.id = UserWebauthnBackend.webAuthnBufferDecode(listItem.id);
}); });
return navigator.credentials.get({ return navigator.credentials.get({
publicKey: credentialRequestOptions.publicKey certificate: credentialRequestOptions.certificate
}); });
}) })
.then((assertion) => { .then((assertion) => {
@@ -692,7 +709,7 @@ class LoginPage extends React.Component {
> >
<CountDownInput <CountDownInput
disabled={this.state.username?.length === 0 || !this.state.validEmailOrPhone} disabled={this.state.username?.length === 0 || !this.state.validEmailOrPhone}
onButtonClickArgs={[this.state.username, "", Setting.getApplicationOrgName(application), true]} onButtonClickArgs={[this.state.username, this.state.validEmail ? "email" : "phone", Setting.getApplicationName(application)]}
/> />
</Form.Item> </Form.Item>
) : ( ) : (

View File

@@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
import React from "react"; import React from "react";
import {Result, Button} from "antd"; import {Button, Result} from "antd";
import i18next from "i18next"; import i18next from "i18next";
import {authConfig} from "./Auth"; import {authConfig} from "./Auth";
import * as Util from "./Util"; import * as Util from "./Util";

View File

@@ -14,7 +14,7 @@
import React from "react"; import React from "react";
import {Link} from "react-router-dom"; import {Link} from "react-router-dom";
import {Form, Input, Checkbox, Button, Row, Col, Result, Modal} from "antd"; import {Button, Checkbox, Col, Form, Input, Modal, Result, Row} from "antd";
import * as Setting from "../Setting"; import * as Setting from "../Setting";
import * as AuthBackend from "./AuthBackend"; import * as AuthBackend from "./AuthBackend";
import i18next from "i18next"; import i18next from "i18next";
@@ -79,19 +79,28 @@ class SignupPage extends React.Component {
} }
UNSAFE_componentWillMount() { UNSAFE_componentWillMount() {
if (this.state.applicationName !== undefined) { let applicationName = this.state.applicationName;
this.getApplication(); const oAuthParams = Util.getOAuthGetParameters();
if (oAuthParams !== null) {
applicationName = oAuthParams.state;
this.setState({applicationName: oAuthParams.state});
const signinUrl = window.location.href.replace("/signup/oauth/authorize", "/login/oauth/authorize");
sessionStorage.setItem("signinUrl", signinUrl);
}
if (applicationName !== undefined) {
this.getApplication(applicationName);
} else { } else {
Util.showMessage("error", `Unknown application name: ${this.state.applicationName}`); Util.showMessage("error", `Unknown application name: ${applicationName}`);
} }
} }
getApplication() { getApplication(applicationName) {
if (this.state.applicationName === undefined) { if (applicationName === undefined) {
return; return;
} }
ApplicationBackend.getApplication("admin", this.state.applicationName) ApplicationBackend.getApplication("admin", applicationName)
.then((application) => { .then((application) => {
this.setState({ this.setState({
application: application, application: application,

View File

@@ -13,7 +13,7 @@
// limitations under the License. // limitations under the License.
import React from "react"; import React from "react";
import {Alert, Button, message, Result} from "antd"; import {Alert, Button, Result, message} from "antd";
export function showMessage(type, text) { export function showMessage(type, text) {
if (type === "success") { if (type === "success") {
@@ -103,6 +103,7 @@ export function getOAuthGetParameters(params) {
const codeChallenge = getRefinedValue(queries.get("code_challenge")); const codeChallenge = getRefinedValue(queries.get("code_challenge"));
const samlRequest = getRefinedValue(queries.get("SAMLRequest")); const samlRequest = getRefinedValue(queries.get("SAMLRequest"));
const relayState = getRefinedValue(queries.get("RelayState")); const relayState = getRefinedValue(queries.get("RelayState"));
const noRedirect = getRefinedValue(queries.get("noRedirect"));
if ((clientId === undefined || clientId === null || clientId === "") && (samlRequest === "" || samlRequest === undefined)) { if ((clientId === undefined || clientId === null || clientId === "") && (samlRequest === "" || samlRequest === undefined)) {
// login // login
@@ -120,6 +121,7 @@ export function getOAuthGetParameters(params) {
codeChallenge: codeChallenge, codeChallenge: codeChallenge,
samlRequest: samlRequest, samlRequest: samlRequest,
relayState: relayState, relayState: relayState,
noRedirect: noRedirect,
}; };
} }
} }

View File

@@ -21,15 +21,15 @@ export function registerWebauthnCredential() {
}) })
.then(res => res.json()) .then(res => res.json())
.then((credentialCreationOptions) => { .then((credentialCreationOptions) => {
credentialCreationOptions.publicKey.challenge = webAuthnBufferDecode(credentialCreationOptions.publicKey.challenge); credentialCreationOptions.certificate.challenge = webAuthnBufferDecode(credentialCreationOptions.certificate.challenge);
credentialCreationOptions.publicKey.user.id = webAuthnBufferDecode(credentialCreationOptions.publicKey.user.id); credentialCreationOptions.certificate.user.id = webAuthnBufferDecode(credentialCreationOptions.certificate.user.id);
if (credentialCreationOptions.publicKey.excludeCredentials) { if (credentialCreationOptions.certificate.excludeCredentials) {
for (var i = 0; i < credentialCreationOptions.publicKey.excludeCredentials.length; i++) { for (var i = 0; i < credentialCreationOptions.certificate.excludeCredentials.length; i++) {
credentialCreationOptions.publicKey.excludeCredentials[i].id = webAuthnBufferDecode(credentialCreationOptions.publicKey.excludeCredentials[i].id); credentialCreationOptions.certificate.excludeCredentials[i].id = webAuthnBufferDecode(credentialCreationOptions.certificate.excludeCredentials[i].id);
} }
} }
return navigator.credentials.create({ return navigator.credentials.create({
publicKey: credentialCreationOptions.publicKey certificate: credentialCreationOptions.certificate
}); });
}) })
.then((credential) => { .then((credential) => {

View File

@@ -51,11 +51,11 @@
"Bit size": "Bitgröße", "Bit size": "Bitgröße",
"Bit size - Tooltip": "Bit Größe - Tooltip", "Bit size - Tooltip": "Bit Größe - Tooltip",
"Copy private key": "Privaten Schlüssel kopieren", "Copy private key": "Privaten Schlüssel kopieren",
"Copy public key": "Öffentlichen Schlüssel kopieren", "Copy certificate": "Kopieren des Zertifikats",
"Crypto algorithm": "Crypto-Algorithmus", "Crypto algorithm": "Crypto-Algorithmus",
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip", "Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
"Download private key": "Privaten Schlüssel herunterladen", "Download private key": "Privaten Schlüssel herunterladen",
"Download public key": "Öffentlichen Schlüssel herunterladen", "Download certificate": "Zertifikat herunterladen",
"Edit Cert": "Zitat bearbeiten", "Edit Cert": "Zitat bearbeiten",
"Expire in years": "Gültig in Jahren", "Expire in years": "Gültig in Jahren",
"Expire in years - Tooltip": "Verfällt in Jahren - Tooltip", "Expire in years - Tooltip": "Verfällt in Jahren - Tooltip",
@@ -63,9 +63,9 @@
"Private key": "Privater Schlüssel", "Private key": "Privater Schlüssel",
"Private key - Tooltip": "Privater Schlüssel - Tooltip", "Private key - Tooltip": "Privater Schlüssel - Tooltip",
"Private key copied to clipboard successfully": "Privater Schlüssel erfolgreich in die Zwischenablage kopiert", "Private key copied to clipboard successfully": "Privater Schlüssel erfolgreich in die Zwischenablage kopiert",
"Public key": "Öffentlicher Schlüssel", "Certificate": "Zertifikat",
"Public key - Tooltip": "Öffentlicher Schlüssel - Tooltip", "Certificate - Tooltip": "Zertifikat - Tooltip",
"Public key copied to clipboard successfully": "Öffentlicher Schlüssel erfolgreich in die Zwischenablage kopiert", "Certificate copied to clipboard successfully": "Das Zertifikat wurde erfolgreich in die Zwischenablage kopiert",
"Scope": "Bereich", "Scope": "Bereich",
"Scope - Tooltip": "Bereich - Tooltip", "Scope - Tooltip": "Bereich - Tooltip",
"Type": "Typ", "Type": "Typ",
@@ -93,6 +93,7 @@
"Please input your username!": "Bitte geben Sie Ihren Benutzernamen ein!", "Please input your username!": "Bitte geben Sie Ihren Benutzernamen ein!",
"Reset": "Reset", "Reset": "Reset",
"Retrieve password": "Passwort abrufen", "Retrieve password": "Passwort abrufen",
"Unknown forget type": "Unknown forget type",
"Verify": "Überprüfen" "Verify": "Überprüfen"
}, },
"general": { "general": {
@@ -187,6 +188,7 @@
"Signup application - Tooltip": "Signup application - Tooltip", "Signup application - Tooltip": "Signup application - Tooltip",
"Sorry, the page you visited does not exist.": "Die von Ihnen besuchte Seite existiert leider nicht.", "Sorry, the page you visited does not exist.": "Die von Ihnen besuchte Seite existiert leider nicht.",
"Sorry, the user you visited does not exist or you are not authorized to access this user.": "Sorry, the user you visited does not exist or you are not authorized to access this user.", "Sorry, the user you visited does not exist or you are not authorized to access this user.": "Sorry, the user you visited does not exist or you are not authorized to access this user.",
"Sorry, you do not have permission to access this page.": "Sorry, you do not have permission to access this page.",
"State": "State", "State": "State",
"State - Tooltip": "State - Tooltip", "State - Tooltip": "State - Tooltip",
"Swagger": "Swagger", "Swagger": "Swagger",
@@ -345,7 +347,8 @@
"New Permission": "New Permission", "New Permission": "New Permission",
"Resource type": "Ressourcentyp", "Resource type": "Ressourcentyp",
"Resource type - Tooltip": "Ressourcentyp - Tooltip", "Resource type - Tooltip": "Ressourcentyp - Tooltip",
"Resources": "Ressourcen" "Resources": "Ressourcen",
"Resources - Tooltip": "Resources - Tooltip"
}, },
"product": { "product": {
"Alipay": "Alipay", "Alipay": "Alipay",
@@ -423,7 +426,7 @@
"Host": "Host", "Host": "Host",
"Host - Tooltip": "Unique string-style identifier", "Host - Tooltip": "Unique string-style identifier",
"IdP": "IdP", "IdP": "IdP",
"IdP public key": "IdP-öffentlicher Schlüssel", "IdP certificate": "IdP-öffentlicher Schlüssel",
"Issuer URL": "Ausgabe-URL", "Issuer URL": "Ausgabe-URL",
"Issuer URL - Tooltip": "Ausgabe-URL - Tooltip", "Issuer URL - Tooltip": "Ausgabe-URL - Tooltip",
"Link copied to clipboard successfully": "Link erfolgreich in die Zwischenablage kopiert", "Link copied to clipboard successfully": "Link erfolgreich in die Zwischenablage kopiert",
@@ -663,4 +666,4 @@
"URL - Tooltip": "URL - Tooltip", "URL - Tooltip": "URL - Tooltip",
"Value": "Wert" "Value": "Wert"
} }
} }

View File

@@ -51,11 +51,11 @@
"Bit size": "Bit size", "Bit size": "Bit size",
"Bit size - Tooltip": "Bit size - Tooltip", "Bit size - Tooltip": "Bit size - Tooltip",
"Copy private key": "Copy private key", "Copy private key": "Copy private key",
"Copy public key": "Copy public key", "Copy certificate": "Copy certificate",
"Crypto algorithm": "Crypto algorithm", "Crypto algorithm": "Crypto algorithm",
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip", "Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
"Download private key": "Download private key", "Download private key": "Download private key",
"Download public key": "Download public key", "Download certificate": "Download certificate",
"Edit Cert": "Edit Cert", "Edit Cert": "Edit Cert",
"Expire in years": "Expire in years", "Expire in years": "Expire in years",
"Expire in years - Tooltip": "Expire in years - Tooltip", "Expire in years - Tooltip": "Expire in years - Tooltip",
@@ -63,9 +63,9 @@
"Private key": "Private key", "Private key": "Private key",
"Private key - Tooltip": "Private key - Tooltip", "Private key - Tooltip": "Private key - Tooltip",
"Private key copied to clipboard successfully": "Private key copied to clipboard successfully", "Private key copied to clipboard successfully": "Private key copied to clipboard successfully",
"Public key": "Public key", "Certificate": "Certificate",
"Public key - Tooltip": "Public key - Tooltip", "Certificate - Tooltip": "Certificate - Tooltip",
"Public key copied to clipboard successfully": "Public key copied to clipboard successfully", "Certificate copied to clipboard successfully": "Certificate copied to clipboard successfully",
"Scope": "Scope", "Scope": "Scope",
"Scope - Tooltip": "Scope - Tooltip", "Scope - Tooltip": "Scope - Tooltip",
"Type": "Type", "Type": "Type",
@@ -93,6 +93,7 @@
"Please input your username!": "Please input your username!", "Please input your username!": "Please input your username!",
"Reset": "Reset", "Reset": "Reset",
"Retrieve password": "Retrieve password", "Retrieve password": "Retrieve password",
"Unknown forget type": "Unknown forget type",
"Verify": "Verify" "Verify": "Verify"
}, },
"general": { "general": {
@@ -187,6 +188,7 @@
"Signup application - Tooltip": "Signup application - Tooltip", "Signup application - Tooltip": "Signup application - Tooltip",
"Sorry, the page you visited does not exist.": "Sorry, the page you visited does not exist.", "Sorry, the page you visited does not exist.": "Sorry, the page you visited does not exist.",
"Sorry, the user you visited does not exist or you are not authorized to access this user.": "Sorry, the user you visited does not exist or you are not authorized to access this user.", "Sorry, the user you visited does not exist or you are not authorized to access this user.": "Sorry, the user you visited does not exist or you are not authorized to access this user.",
"Sorry, you do not have permission to access this page.": "Sorry, you do not have permission to access this page.",
"State": "State", "State": "State",
"State - Tooltip": "State - Tooltip", "State - Tooltip": "State - Tooltip",
"Swagger": "Swagger", "Swagger": "Swagger",
@@ -345,7 +347,8 @@
"New Permission": "New Permission", "New Permission": "New Permission",
"Resource type": "Resource type", "Resource type": "Resource type",
"Resource type - Tooltip": "Resource type - Tooltip", "Resource type - Tooltip": "Resource type - Tooltip",
"Resources": "Resources" "Resources": "Resources",
"Resources - Tooltip": "Resources - Tooltip"
}, },
"product": { "product": {
"Alipay": "Alipay", "Alipay": "Alipay",
@@ -423,7 +426,7 @@
"Host": "Host", "Host": "Host",
"Host - Tooltip": "Host - Tooltip", "Host - Tooltip": "Host - Tooltip",
"IdP": "IdP", "IdP": "IdP",
"IdP public key": "IdP public key", "IdP certificate": "IdP certificate",
"Issuer URL": "Issuer URL", "Issuer URL": "Issuer URL",
"Issuer URL - Tooltip": "Issuer URL - Tooltip", "Issuer URL - Tooltip": "Issuer URL - Tooltip",
"Link copied to clipboard successfully": "Link copied to clipboard successfully", "Link copied to clipboard successfully": "Link copied to clipboard successfully",
@@ -663,4 +666,4 @@
"URL - Tooltip": "URL - Tooltip", "URL - Tooltip": "URL - Tooltip",
"Value": "Value" "Value": "Value"
} }
} }

View File

@@ -51,21 +51,21 @@
"Bit size": "Taille du bit", "Bit size": "Taille du bit",
"Bit size - Tooltip": "Taille du bit - Infobulle", "Bit size - Tooltip": "Taille du bit - Infobulle",
"Copy private key": "Copier la clé privée", "Copy private key": "Copier la clé privée",
"Copy public key": "Copier la clé publique", "Copy certificate": "Copier le certificate",
"Crypto algorithm": "Algorithme de cryptomonnaie", "Crypto algorithm": "Algorithme de cryptomonnaie",
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip", "Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
"Download private key": "Télécharger la clé privée", "Download private key": "Télécharger la clé privée",
"Download public key": "Télécharger la clé publique", "Download certificate": "Télécharger le certificate",
"Edit Cert": "Modifier le certificat", "Edit Cert": "Modifier le certificate",
"Expire in years": "Expire dans les années", "Expire in years": "Expire dans les années",
"Expire in years - Tooltip": "Expire dans les années - infobulle", "Expire in years - Tooltip": "Expire dans les années - infobulle",
"New Cert": "New Cert", "New Cert": "New Cert",
"Private key": "Clé privée", "Private key": "Clé privée",
"Private key - Tooltip": "Clé privée - Infobulle", "Private key - Tooltip": "Clé privée - Infobulle",
"Private key copied to clipboard successfully": "Clé privée copiée dans le presse-papiers avec succès", "Private key copied to clipboard successfully": "Clé privée copiée dans le presse-papiers avec succès",
"Public key": "Clé publique", "Certificate": "certificate",
"Public key - Tooltip": "Clé publique - Infobulle", "Certificate - Tooltip": "certificate - Infobulle",
"Public key copied to clipboard successfully": "Clé publique copiée dans le presse-papiers avec succès", "Certificate copied to clipboard successfully": "Le certificate a été copié avec succès dans le presse-papiers",
"Scope": "Périmètre d'application", "Scope": "Périmètre d'application",
"Scope - Tooltip": "Scope - Infobulle", "Scope - Tooltip": "Scope - Infobulle",
"Type": "Type de texte", "Type": "Type de texte",
@@ -93,6 +93,7 @@
"Please input your username!": "Veuillez entrer votre nom d'utilisateur !", "Please input your username!": "Veuillez entrer votre nom d'utilisateur !",
"Reset": "Reset", "Reset": "Reset",
"Retrieve password": "Récupérer le mot de passe", "Retrieve password": "Récupérer le mot de passe",
"Unknown forget type": "Unknown forget type",
"Verify": "Vérifier" "Verify": "Vérifier"
}, },
"general": { "general": {
@@ -187,6 +188,7 @@
"Signup application - Tooltip": "Signup application - Tooltip", "Signup application - Tooltip": "Signup application - Tooltip",
"Sorry, the page you visited does not exist.": "Désolé, la page que vous avez visitée n'existe pas.", "Sorry, the page you visited does not exist.": "Désolé, la page que vous avez visitée n'existe pas.",
"Sorry, the user you visited does not exist or you are not authorized to access this user.": "Sorry, the user you visited does not exist or you are not authorized to access this user.", "Sorry, the user you visited does not exist or you are not authorized to access this user.": "Sorry, the user you visited does not exist or you are not authorized to access this user.",
"Sorry, you do not have permission to access this page.": "Désolé, vous n'avez pas la permission d'accéder à cette page.",
"State": "State", "State": "State",
"State - Tooltip": "State - Tooltip", "State - Tooltip": "State - Tooltip",
"Swagger": "Swagger", "Swagger": "Swagger",
@@ -345,7 +347,8 @@
"New Permission": "New Permission", "New Permission": "New Permission",
"Resource type": "Type de ressource", "Resource type": "Type de ressource",
"Resource type - Tooltip": "Type de ressource - infobulle", "Resource type - Tooltip": "Type de ressource - infobulle",
"Resources": "Ressource" "Resources": "Ressource",
"Resources - Tooltip": "Resources - Tooltip"
}, },
"product": { "product": {
"Alipay": "Alipay", "Alipay": "Alipay",
@@ -423,7 +426,7 @@
"Host": "Hôte", "Host": "Hôte",
"Host - Tooltip": "Unique string-style identifier", "Host - Tooltip": "Unique string-style identifier",
"IdP": "IDP", "IdP": "IDP",
"IdP public key": "Clé publique IdP", "IdP certificate": "Clé publique IdP",
"Issuer URL": "URL de l'émetteur", "Issuer URL": "URL de l'émetteur",
"Issuer URL - Tooltip": "URL de l'émetteur - infobulle", "Issuer URL - Tooltip": "URL de l'émetteur - infobulle",
"Link copied to clipboard successfully": "Lien copié dans le presse-papiers avec succès", "Link copied to clipboard successfully": "Lien copié dans le presse-papiers avec succès",
@@ -663,4 +666,4 @@
"URL - Tooltip": "URL - Info-bulle", "URL - Tooltip": "URL - Info-bulle",
"Value": "Valeur" "Value": "Valeur"
} }
} }

View File

@@ -51,11 +51,11 @@
"Bit size": "ビットサイズ", "Bit size": "ビットサイズ",
"Bit size - Tooltip": "ビットサイズ - ツールチップ", "Bit size - Tooltip": "ビットサイズ - ツールチップ",
"Copy private key": "秘密鍵をコピー", "Copy private key": "秘密鍵をコピー",
"Copy public key": "公開鍵をコピー", "Copy certificate": "証明書をコピーします",
"Crypto algorithm": "暗号化アルゴリズム", "Crypto algorithm": "暗号化アルゴリズム",
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip", "Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
"Download private key": "秘密鍵をダウンロード", "Download private key": "秘密鍵をダウンロード",
"Download public key": "公開鍵をダウンロード", "Download certificate": "証明書をダウンロードします",
"Edit Cert": "Certを編集", "Edit Cert": "Certを編集",
"Expire in years": "有効期限", "Expire in years": "有効期限",
"Expire in years - Tooltip": "年間有効期限 - ツールチップ", "Expire in years - Tooltip": "年間有効期限 - ツールチップ",
@@ -63,9 +63,9 @@
"Private key": "Private key", "Private key": "Private key",
"Private key - Tooltip": "Private key - Tooltip", "Private key - Tooltip": "Private key - Tooltip",
"Private key copied to clipboard successfully": "秘密鍵を正常にクリップボードにコピーしました", "Private key copied to clipboard successfully": "秘密鍵を正常にクリップボードにコピーしました",
"Public key": "公開キー", "Certificate": "Certificate",
"Public key - Tooltip": "Public key - Tooltip", "Certificate - Tooltip": "Certificate - Tooltip",
"Public key copied to clipboard successfully": "公開鍵を正常にクリップボードにコピーました", "Certificate copied to clipboard successfully": "証明書はクリップボードに正常にコピーされました",
"Scope": "スコープ", "Scope": "スコープ",
"Scope - Tooltip": "スコープ → ツールチップ", "Scope - Tooltip": "スコープ → ツールチップ",
"Type": "タイプ", "Type": "タイプ",
@@ -93,6 +93,7 @@
"Please input your username!": "ユーザー名を入力してください!", "Please input your username!": "ユーザー名を入力してください!",
"Reset": "Reset", "Reset": "Reset",
"Retrieve password": "パスワードの取得", "Retrieve password": "パスワードの取得",
"Unknown forget type": "Unknown forget type",
"Verify": "確認する" "Verify": "確認する"
}, },
"general": { "general": {
@@ -187,6 +188,7 @@
"Signup application - Tooltip": "Signup application - Tooltip", "Signup application - Tooltip": "Signup application - Tooltip",
"Sorry, the page you visited does not exist.": "申し訳ありませんが、訪問したページは存在しません。", "Sorry, the page you visited does not exist.": "申し訳ありませんが、訪問したページは存在しません。",
"Sorry, the user you visited does not exist or you are not authorized to access this user.": "Sorry, the user you visited does not exist or you are not authorized to access this user.", "Sorry, the user you visited does not exist or you are not authorized to access this user.": "Sorry, the user you visited does not exist or you are not authorized to access this user.",
"Sorry, you do not have permission to access this page.": "申し訳ありませんが、このページにアクセスする権限がありません。",
"State": "State", "State": "State",
"State - Tooltip": "State - Tooltip", "State - Tooltip": "State - Tooltip",
"Swagger": "Swagger", "Swagger": "Swagger",
@@ -345,7 +347,8 @@
"New Permission": "New Permission", "New Permission": "New Permission",
"Resource type": "リソースタイプ", "Resource type": "リソースタイプ",
"Resource type - Tooltip": "リソースタイプ - ツールチップ", "Resource type - Tooltip": "リソースタイプ - ツールチップ",
"Resources": "リソース" "Resources": "リソース",
"Resources - Tooltip": "Resources - Tooltip"
}, },
"product": { "product": {
"Alipay": "Alipay", "Alipay": "Alipay",
@@ -423,7 +426,7 @@
"Host": "ホスト", "Host": "ホスト",
"Host - Tooltip": "Unique string-style identifier", "Host - Tooltip": "Unique string-style identifier",
"IdP": "IdP", "IdP": "IdP",
"IdP public key": "IdP public key", "IdP certificate": "IdP certificate",
"Issuer URL": "Issuer URL", "Issuer URL": "Issuer URL",
"Issuer URL - Tooltip": "Issuer URL - ツールチップ", "Issuer URL - Tooltip": "Issuer URL - ツールチップ",
"Link copied to clipboard successfully": "リンクをクリップボードにコピーしました", "Link copied to clipboard successfully": "リンクをクリップボードにコピーしました",
@@ -663,4 +666,4 @@
"URL - Tooltip": "URL → ツールチップ", "URL - Tooltip": "URL → ツールチップ",
"Value": "値" "Value": "値"
} }
} }

View File

@@ -51,11 +51,11 @@
"Bit size": "Bit size", "Bit size": "Bit size",
"Bit size - Tooltip": "Bit size - Tooltip", "Bit size - Tooltip": "Bit size - Tooltip",
"Copy private key": "Copy private key", "Copy private key": "Copy private key",
"Copy public key": "Copy public key", "Copy certificate": "Copy certificate",
"Crypto algorithm": "Crypto algorithm", "Crypto algorithm": "Crypto algorithm",
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip", "Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
"Download private key": "Download private key", "Download private key": "Download private key",
"Download public key": "Download public key", "Download certificate": "Download certificate",
"Edit Cert": "Edit Cert", "Edit Cert": "Edit Cert",
"Expire in years": "Expire in years", "Expire in years": "Expire in years",
"Expire in years - Tooltip": "Expire in years - Tooltip", "Expire in years - Tooltip": "Expire in years - Tooltip",
@@ -63,9 +63,9 @@
"Private key": "Private key", "Private key": "Private key",
"Private key - Tooltip": "Private key - Tooltip", "Private key - Tooltip": "Private key - Tooltip",
"Private key copied to clipboard successfully": "Private key copied to clipboard successfully", "Private key copied to clipboard successfully": "Private key copied to clipboard successfully",
"Public key": "Public key", "Certificate": "Certificate",
"Public key - Tooltip": "Public key - Tooltip", "Certificate - Tooltip": "Certificate - Tooltip",
"Public key copied to clipboard successfully": "Public key copied to clipboard successfully", "Certificate copied to clipboard successfully": "Certificate copied to clipboard successfully",
"Scope": "Scope", "Scope": "Scope",
"Scope - Tooltip": "Scope - Tooltip", "Scope - Tooltip": "Scope - Tooltip",
"Type": "Type", "Type": "Type",
@@ -93,6 +93,7 @@
"Please input your username!": "Please input your username!", "Please input your username!": "Please input your username!",
"Reset": "Reset", "Reset": "Reset",
"Retrieve password": "Retrieve password", "Retrieve password": "Retrieve password",
"Unknown forget type": "Unknown forget type",
"Verify": "Verify" "Verify": "Verify"
}, },
"general": { "general": {
@@ -187,6 +188,7 @@
"Signup application - Tooltip": "Signup application - Tooltip", "Signup application - Tooltip": "Signup application - Tooltip",
"Sorry, the page you visited does not exist.": "Sorry, the page you visited does not exist.", "Sorry, the page you visited does not exist.": "Sorry, the page you visited does not exist.",
"Sorry, the user you visited does not exist or you are not authorized to access this user.": "Sorry, the user you visited does not exist or you are not authorized to access this user.", "Sorry, the user you visited does not exist or you are not authorized to access this user.": "Sorry, the user you visited does not exist or you are not authorized to access this user.",
"Sorry, you do not have permission to access this page.": "Sorry, you do not have permission to access this page.",
"State": "State", "State": "State",
"State - Tooltip": "State - Tooltip", "State - Tooltip": "State - Tooltip",
"Swagger": "Swagger", "Swagger": "Swagger",
@@ -345,7 +347,8 @@
"New Permission": "New Permission", "New Permission": "New Permission",
"Resource type": "Resource type", "Resource type": "Resource type",
"Resource type - Tooltip": "Resource type - Tooltip", "Resource type - Tooltip": "Resource type - Tooltip",
"Resources": "Resources" "Resources": "Resources",
"Resources - Tooltip": "Resources - Tooltip"
}, },
"product": { "product": {
"Alipay": "Alipay", "Alipay": "Alipay",
@@ -423,7 +426,7 @@
"Host": "Host", "Host": "Host",
"Host - Tooltip": "Unique string-style identifier", "Host - Tooltip": "Unique string-style identifier",
"IdP": "IdP", "IdP": "IdP",
"IdP public key": "IdP public key", "IdP certificate": "IdP certificate",
"Issuer URL": "Issuer URL", "Issuer URL": "Issuer URL",
"Issuer URL - Tooltip": "Issuer URL - Tooltip", "Issuer URL - Tooltip": "Issuer URL - Tooltip",
"Link copied to clipboard successfully": "Link copied to clipboard successfully", "Link copied to clipboard successfully": "Link copied to clipboard successfully",
@@ -663,4 +666,4 @@
"URL - Tooltip": "URL - Tooltip", "URL - Tooltip": "URL - Tooltip",
"Value": "Value" "Value": "Value"
} }
} }

View File

@@ -51,11 +51,11 @@
"Bit size": "Размер бита", "Bit size": "Размер бита",
"Bit size - Tooltip": "Размер бита - Подсказка", "Bit size - Tooltip": "Размер бита - Подсказка",
"Copy private key": "Копировать закрытый ключ", "Copy private key": "Копировать закрытый ключ",
"Copy public key": "Копировать открытый ключ", "Copy certificate": "Копирование сертификата",
"Crypto algorithm": "Алгоритм крипто", "Crypto algorithm": "Алгоритм крипто",
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip", "Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
"Download private key": "Скачать закрытый ключ", "Download private key": "Скачать закрытый ключ",
"Download public key": "Скачать открытый ключ", "Download certificate": "Скачать сертификат",
"Edit Cert": "Изменить сертификат", "Edit Cert": "Изменить сертификат",
"Expire in years": "Истекает через годы", "Expire in years": "Истекает через годы",
"Expire in years - Tooltip": "Истекает через годы - Подсказка", "Expire in years - Tooltip": "Истекает через годы - Подсказка",
@@ -63,9 +63,9 @@
"Private key": "Приватный ключ", "Private key": "Приватный ключ",
"Private key - Tooltip": "Приватный ключ - Подсказка", "Private key - Tooltip": "Приватный ключ - Подсказка",
"Private key copied to clipboard successfully": "Приватный ключ скопирован в буфер обмена", "Private key copied to clipboard successfully": "Приватный ключ скопирован в буфер обмена",
"Public key": "Публичный ключ", "Certificate": "сертификат",
"Public key - Tooltip": "Открытый ключ - Подсказка", "Certificate - Tooltip": "сертификат - Подсказка",
"Public key copied to clipboard successfully": "Открытый ключ успешно скопирован в буфер обмена", "Certificate copied to clipboard successfully": "Сертификат успешно скопирован в буфер обмена",
"Scope": "Сфера охвата", "Scope": "Сфера охвата",
"Scope - Tooltip": "Область применения - Подсказка", "Scope - Tooltip": "Область применения - Подсказка",
"Type": "Тип", "Type": "Тип",
@@ -93,6 +93,7 @@
"Please input your username!": "Пожалуйста, введите ваше имя пользователя!", "Please input your username!": "Пожалуйста, введите ваше имя пользователя!",
"Reset": "Reset", "Reset": "Reset",
"Retrieve password": "Получить пароль", "Retrieve password": "Получить пароль",
"Unknown forget type": "Unknown forget type",
"Verify": "Подтвердить" "Verify": "Подтвердить"
}, },
"general": { "general": {
@@ -187,6 +188,7 @@
"Signup application - Tooltip": "Signup application - Tooltip", "Signup application - Tooltip": "Signup application - Tooltip",
"Sorry, the page you visited does not exist.": "Извините, посещенная вами страница не существует.", "Sorry, the page you visited does not exist.": "Извините, посещенная вами страница не существует.",
"Sorry, the user you visited does not exist or you are not authorized to access this user.": "Sorry, the user you visited does not exist or you are not authorized to access this user.", "Sorry, the user you visited does not exist or you are not authorized to access this user.": "Sorry, the user you visited does not exist or you are not authorized to access this user.",
"Sorry, you do not have permission to access this page.": "Извините, вы не имеете права доступа к этой странице.",
"State": "State", "State": "State",
"State - Tooltip": "State - Tooltip", "State - Tooltip": "State - Tooltip",
"Swagger": "Swagger", "Swagger": "Swagger",
@@ -345,7 +347,8 @@
"New Permission": "New Permission", "New Permission": "New Permission",
"Resource type": "Тип ресурса", "Resource type": "Тип ресурса",
"Resource type - Tooltip": "Тип ресурса - Подсказка", "Resource type - Tooltip": "Тип ресурса - Подсказка",
"Resources": "Ресурсы" "Resources": "Ресурсы",
"Resources - Tooltip": "Resources - Tooltip"
}, },
"product": { "product": {
"Alipay": "Alipay", "Alipay": "Alipay",
@@ -423,7 +426,7 @@
"Host": "Хост", "Host": "Хост",
"Host - Tooltip": "Unique string-style identifier", "Host - Tooltip": "Unique string-style identifier",
"IdP": "ИдП", "IdP": "ИдП",
"IdP public key": "Публичный ключ IdP", "IdP certificate": "Публичный ключ IdP",
"Issuer URL": "URL эмитента", "Issuer URL": "URL эмитента",
"Issuer URL - Tooltip": "URL эмитента - Tooltip", "Issuer URL - Tooltip": "URL эмитента - Tooltip",
"Link copied to clipboard successfully": "Ссылка скопирована в буфер обмена", "Link copied to clipboard successfully": "Ссылка скопирована в буфер обмена",
@@ -663,4 +666,4 @@
"URL - Tooltip": "URL - Подсказка", "URL - Tooltip": "URL - Подсказка",
"Value": "Значение" "Value": "Значение"
} }
} }

View File

@@ -51,11 +51,11 @@
"Bit size": "位大小", "Bit size": "位大小",
"Bit size - Tooltip": "位大小 - 工具提示", "Bit size - Tooltip": "位大小 - 工具提示",
"Copy private key": "复制私钥", "Copy private key": "复制私钥",
"Copy public key": "复制公钥", "Copy certificate": "复制证书",
"Crypto algorithm": "加密算法", "Crypto algorithm": "加密算法",
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip", "Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
"Download private key": "下载私钥", "Download private key": "下载私钥",
"Download public key": "下载公钥", "Download certificate": "下载证书",
"Edit Cert": "编辑证书", "Edit Cert": "编辑证书",
"Expire in years": "有效期(年)", "Expire in years": "有效期(年)",
"Expire in years - Tooltip": "到期年份-工具提示", "Expire in years - Tooltip": "到期年份-工具提示",
@@ -63,9 +63,9 @@
"Private key": "私钥", "Private key": "私钥",
"Private key - Tooltip": "私钥 - 工具提示", "Private key - Tooltip": "私钥 - 工具提示",
"Private key copied to clipboard successfully": "私钥已成功复制到剪贴板", "Private key copied to clipboard successfully": "私钥已成功复制到剪贴板",
"Public key": "公钥", "Certificate": "证书",
"Public key - Tooltip": "公钥 - 工具提示", "Certificate - Tooltip": "证书 - 工具提示",
"Public key copied to clipboard successfully": "公钥已成功复制到剪贴板", "Certificate copied to clipboard successfully": "证书已成功复制到剪贴板",
"Scope": "用途", "Scope": "用途",
"Scope - Tooltip": "范围 - 工具提示", "Scope - Tooltip": "范围 - 工具提示",
"Type": "类型", "Type": "类型",
@@ -93,6 +93,7 @@
"Please input your username!": "请输入您的用户名!", "Please input your username!": "请输入您的用户名!",
"Reset": "重置", "Reset": "重置",
"Retrieve password": "找回密码", "Retrieve password": "找回密码",
"Unknown forget type": "未知的忘记密码类型",
"Verify": "验证" "Verify": "验证"
}, },
"general": { "general": {
@@ -187,6 +188,7 @@
"Signup application - Tooltip": "表示用户注册时通过哪个应用注册的", "Signup application - Tooltip": "表示用户注册时通过哪个应用注册的",
"Sorry, the page you visited does not exist.": "抱歉,您访问的页面不存在", "Sorry, the page you visited does not exist.": "抱歉,您访问的页面不存在",
"Sorry, the user you visited does not exist or you are not authorized to access this user.": "抱歉,您访问的用户不存在或您无权访问该用户", "Sorry, the user you visited does not exist or you are not authorized to access this user.": "抱歉,您访问的用户不存在或您无权访问该用户",
"Sorry, you do not have permission to access this page.": "抱歉,您无权访问该页面",
"State": "状态", "State": "状态",
"State - Tooltip": "状态", "State - Tooltip": "状态",
"Swagger": "API文档", "Swagger": "API文档",
@@ -345,7 +347,8 @@
"New Permission": "添加权限", "New Permission": "添加权限",
"Resource type": "资源类型", "Resource type": "资源类型",
"Resource type - Tooltip": "授权资源的类型", "Resource type - Tooltip": "授权资源的类型",
"Resources": "资源" "Resources": "资源",
"Resources - Tooltip": "被授权的资源"
}, },
"product": { "product": {
"Alipay": "支付宝", "Alipay": "支付宝",
@@ -423,7 +426,7 @@
"Host": "主机", "Host": "主机",
"Host - Tooltip": "主机", "Host - Tooltip": "主机",
"IdP": "IdP", "IdP": "IdP",
"IdP public key": "IdP 公钥", "IdP certificate": "IdP 公钥",
"Issuer URL": "发行者网址", "Issuer URL": "发行者网址",
"Issuer URL - Tooltip": "发行者URL - 工具提示", "Issuer URL - Tooltip": "发行者URL - 工具提示",
"Link copied to clipboard successfully": "链接已成功复制到剪贴板", "Link copied to clipboard successfully": "链接已成功复制到剪贴板",
@@ -663,4 +666,4 @@
"URL - Tooltip": "URL", "URL - Tooltip": "URL",
"Value": "值" "Value": "值"
} }
} }