mirror of
https://github.com/casdoor/casdoor.git
synced 2025-08-27 01:40:22 +08:00
Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
6455734807 | ||
![]() |
2eefeaffa7 | ||
![]() |
04eaad1c80 | ||
![]() |
9f084a0799 | ||
![]() |
293b9f1036 | ||
![]() |
437376c472 | ||
![]() |
cc528c5d8c | ||
![]() |
54e2055ffb | ||
![]() |
983a30a2e0 | ||
![]() |
37d0157d41 | ||
![]() |
d4dc236770 | ||
![]() |
596742d782 | ||
![]() |
ce921c00cd | ||
![]() |
3830e443b0 |
@@ -20,5 +20,4 @@ staticBaseUrl = "https://cdn.casbin.org"
|
||||
isDemoMode = false
|
||||
batchSize = 100
|
||||
ldapServerPort = 389
|
||||
languages = en,zh,es,fr,de,id,ja,ko,ru,vi
|
||||
quota = {"organization": -1, "user": -1, "application": -1, "provider": -1}
|
||||
|
@@ -112,13 +112,8 @@ func GetLanguage(language string) string {
|
||||
|
||||
if len(language) < 2 {
|
||||
return "en"
|
||||
}
|
||||
|
||||
language = language[0:2]
|
||||
if strings.Contains(GetConfigString("languages"), language) {
|
||||
return language
|
||||
} else {
|
||||
return "en"
|
||||
return language[0:2]
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -416,22 +416,29 @@ func (c *ApiController) Login() {
|
||||
util.SafeGoroutine(func() { object.AddRecord(record) })
|
||||
} else if provider.Category == "OAuth" {
|
||||
// Sign up via OAuth
|
||||
if !application.EnableSignUp {
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support"), provider.Type, userInfo.Username, userInfo.DisplayName))
|
||||
return
|
||||
}
|
||||
|
||||
if !providerItem.CanSignUp {
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up"), provider.Type, userInfo.Username, userInfo.DisplayName, provider.Type))
|
||||
return
|
||||
}
|
||||
|
||||
if application.EnableLinkWithEmail {
|
||||
// find user that has the same email
|
||||
user = object.GetUserByField(application.Organization, "email", userInfo.Email)
|
||||
if userInfo.Email != "" {
|
||||
// Find existing user with Email
|
||||
user = object.GetUserByField(application.Organization, "email", userInfo.Email)
|
||||
}
|
||||
|
||||
if user == nil && userInfo.Phone != "" {
|
||||
// Find existing user with phone number
|
||||
user = object.GetUserByField(application.Organization, "phone", userInfo.Phone)
|
||||
}
|
||||
}
|
||||
|
||||
if user == nil || user.IsDeleted {
|
||||
if !application.EnableSignUp {
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support"), provider.Type, userInfo.Username, userInfo.DisplayName))
|
||||
return
|
||||
}
|
||||
|
||||
if !providerItem.CanSignUp {
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up"), provider.Type, userInfo.Username, userInfo.DisplayName, provider.Type))
|
||||
return
|
||||
}
|
||||
|
||||
// Handle username conflicts
|
||||
tmpUser := object.GetUser(fmt.Sprintf("%s/%s", application.Organization, userInfo.Username))
|
||||
if tmpUser != nil {
|
||||
|
@@ -24,6 +24,7 @@ import (
|
||||
func (c *ApiController) Enforce() {
|
||||
permissionId := c.Input().Get("permissionId")
|
||||
modelId := c.Input().Get("modelId")
|
||||
resourceId := c.Input().Get("resourceId")
|
||||
|
||||
var request object.CasbinRequest
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &request)
|
||||
@@ -35,17 +36,24 @@ func (c *ApiController) Enforce() {
|
||||
if permissionId != "" {
|
||||
c.Data["json"] = object.Enforce(permissionId, &request)
|
||||
c.ServeJSON()
|
||||
} else {
|
||||
owner, modelName := util.GetOwnerAndNameFromId(modelId)
|
||||
permissions := object.GetPermissionsByModel(owner, modelName)
|
||||
|
||||
res := []bool{}
|
||||
for _, permission := range permissions {
|
||||
res = append(res, object.Enforce(permission.GetId(), &request))
|
||||
}
|
||||
c.Data["json"] = res
|
||||
c.ServeJSON()
|
||||
return
|
||||
}
|
||||
|
||||
permissions := make([]*object.Permission, 0)
|
||||
res := []bool{}
|
||||
|
||||
if modelId != "" {
|
||||
owner, modelName := util.GetOwnerAndNameFromId(modelId)
|
||||
permissions = object.GetPermissionsByModel(owner, modelName)
|
||||
} else {
|
||||
permissions = object.GetPermissionsByResource(resourceId)
|
||||
}
|
||||
|
||||
for _, permission := range permissions {
|
||||
res = append(res, object.Enforce(permission.GetId(), &request))
|
||||
}
|
||||
c.Data["json"] = res
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
func (c *ApiController) BatchEnforce() {
|
||||
|
@@ -86,7 +86,10 @@ func (c *ApiController) GetLdapUsers() {
|
||||
Phone: util.GetMaxLenStr(user.TelephoneNumber, user.Mobile, user.MobileTelephoneNumber),
|
||||
Address: util.GetMaxLenStr(user.RegisteredAddress, user.PostalAddress),
|
||||
})
|
||||
uuids = append(uuids, user.Uuid)
|
||||
|
||||
if user.Uuid != "" {
|
||||
uuids = append(uuids, user.Uuid)
|
||||
}
|
||||
}
|
||||
|
||||
existUuids := object.GetExistUuids(ldapServer.Owner, uuids)
|
||||
@@ -215,10 +218,10 @@ func (c *ApiController) SyncLdapUsers() {
|
||||
|
||||
object.UpdateLdapSyncTime(ldapId)
|
||||
|
||||
exist, failed := object.SyncLdapUsers(owner, users, ldapId)
|
||||
exist, failed, _ := object.SyncLdapUsers(owner, users, ldapId)
|
||||
|
||||
c.ResponseOk(&LdapSyncResp{
|
||||
Exist: *exist,
|
||||
Failed: *failed,
|
||||
Exist: exist,
|
||||
Failed: failed,
|
||||
})
|
||||
}
|
||||
|
22
i18n/util.go
22
i18n/util.go
@@ -73,23 +73,27 @@ func applyData(data1 *I18nData, data2 *I18nData) {
|
||||
}
|
||||
}
|
||||
|
||||
func Translate(lang string, error string) string {
|
||||
tokens := strings.SplitN(error, ":", 2)
|
||||
if !strings.Contains(error, ":") || len(tokens) != 2 {
|
||||
return "Translate Error: " + error
|
||||
func Translate(language string, errorText string) string {
|
||||
tokens := strings.SplitN(errorText, ":", 2)
|
||||
if !strings.Contains(errorText, ":") || len(tokens) != 2 {
|
||||
return fmt.Sprintf("Translate error: the error text doesn't contain \":\", errorText = %s", errorText)
|
||||
}
|
||||
|
||||
if langMap[lang] == nil {
|
||||
file, _ := f.ReadFile("locales/" + lang + "/data.json")
|
||||
if langMap[language] == nil {
|
||||
file, err := f.ReadFile(fmt.Sprintf("locales/%s/data.json", language))
|
||||
if err != nil {
|
||||
return fmt.Sprintf("Translate error: the language \"%s\" is not supported, err = %s", language, err.Error())
|
||||
}
|
||||
|
||||
data := I18nData{}
|
||||
err := util.JsonToStruct(string(file), &data)
|
||||
err = util.JsonToStruct(string(file), &data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
langMap[lang] = data
|
||||
langMap[language] = data
|
||||
}
|
||||
|
||||
res := langMap[lang][tokens[0]][tokens[1]]
|
||||
res := langMap[language][tokens[0]][tokens[1]]
|
||||
if res == "" {
|
||||
res = tokens[1]
|
||||
}
|
||||
|
@@ -179,8 +179,12 @@ func (idp *DingTalkIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, erro
|
||||
return nil, err
|
||||
}
|
||||
|
||||
corpEmail, jobNumber, err := idp.getUserCorpEmail(userId, corpAccessToken)
|
||||
corpMobile, corpEmail, jobNumber, err := idp.getUserCorpEmail(userId, corpAccessToken)
|
||||
if err == nil {
|
||||
if corpMobile != "" {
|
||||
userInfo.Phone = corpMobile
|
||||
}
|
||||
|
||||
if corpEmail != "" {
|
||||
userInfo.Email = corpEmail
|
||||
}
|
||||
@@ -264,27 +268,29 @@ func (idp *DingTalkIdProvider) getUserId(unionId string, accessToken string) (st
|
||||
return data.Result.UserId, nil
|
||||
}
|
||||
|
||||
func (idp *DingTalkIdProvider) getUserCorpEmail(userId string, accessToken string) (string, string, error) {
|
||||
func (idp *DingTalkIdProvider) getUserCorpEmail(userId string, accessToken string) (string, string, string, error) {
|
||||
// https://open.dingtalk.com/document/isvapp/query-user-details
|
||||
body := make(map[string]string)
|
||||
body["userid"] = userId
|
||||
respBytes, err := idp.postWithBody(body, "https://oapi.dingtalk.com/topapi/v2/user/get?access_token="+accessToken)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
return "", "", "", err
|
||||
}
|
||||
|
||||
var data struct {
|
||||
ErrMessage string `json:"errmsg"`
|
||||
Result struct {
|
||||
Mobile string `json:"mobile"`
|
||||
Email string `json:"email"`
|
||||
JobNumber string `json:"job_number"`
|
||||
} `json:"result"`
|
||||
}
|
||||
err = json.Unmarshal(respBytes, &data)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
return "", "", "", err
|
||||
}
|
||||
if data.ErrMessage != "ok" {
|
||||
return "", "", fmt.Errorf(data.ErrMessage)
|
||||
return "", "", "", fmt.Errorf(data.ErrMessage)
|
||||
}
|
||||
return data.Result.Email, data.Result.JobNumber, nil
|
||||
return data.Result.Mobile, data.Result.Email, data.Result.JobNumber, nil
|
||||
}
|
||||
|
2
main.go
2
main.go
@@ -59,8 +59,8 @@ func main() {
|
||||
beego.InsertFilter("*", beego.BeforeRouter, routers.AutoSigninFilter)
|
||||
beego.InsertFilter("*", beego.BeforeRouter, routers.CorsFilter)
|
||||
beego.InsertFilter("*", beego.BeforeRouter, routers.AuthzFilter)
|
||||
beego.InsertFilter("*", beego.BeforeRouter, routers.RecordMessage)
|
||||
beego.InsertFilter("*", beego.BeforeRouter, routers.PrometheusFilter)
|
||||
beego.InsertFilter("*", beego.BeforeRouter, routers.RecordMessage)
|
||||
|
||||
beego.BConfig.WebConfig.Session.SessionOn = true
|
||||
beego.BConfig.WebConfig.Session.SessionName = "casdoor_session_id"
|
||||
|
@@ -134,6 +134,24 @@ func getCert(owner string, name string) *Cert {
|
||||
}
|
||||
}
|
||||
|
||||
func getCertByName(name string) *Cert {
|
||||
if name == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
cert := Cert{Name: name}
|
||||
existed, err := adapter.Engine.Get(&cert)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if existed {
|
||||
return &cert
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func GetCert(id string) *Cert {
|
||||
owner, name := util.GetOwnerAndNameFromId(id)
|
||||
return getCert(owner, name)
|
||||
@@ -189,7 +207,7 @@ func (p *Cert) GetId() string {
|
||||
|
||||
func getCertByApplication(application *Application) *Cert {
|
||||
if application.Cert != "" {
|
||||
return getCert("admin", application.Cert)
|
||||
return getCertByName(application.Cert)
|
||||
} else {
|
||||
return GetDefaultCert()
|
||||
}
|
||||
|
@@ -321,6 +321,10 @@ func CheckUserPermission(requestUserId, userId string, strict bool, lang string)
|
||||
}
|
||||
|
||||
func CheckAccessPermission(userId string, application *Application) (bool, error) {
|
||||
if userId == "built-in/admin" {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
permissions := GetPermissions(application.Organization)
|
||||
allowed := true
|
||||
var err error
|
||||
|
@@ -87,11 +87,13 @@ func (l *LdapAutoSynchronizer) syncRoutine(ldap *Ldap, stopChan chan struct{}) {
|
||||
logs.Warning(fmt.Sprintf("autoSync failed for %s, error %s", ldap.Id, err))
|
||||
continue
|
||||
}
|
||||
existed, failed := SyncLdapUsers(ldap.Owner, LdapUsersToLdapRespUsers(users), ldap.Id)
|
||||
if len(*failed) != 0 {
|
||||
logs.Warning(fmt.Sprintf("ldap autosync,%d new users,but %d user failed during :", len(users)-len(*existed)-len(*failed), len(*failed)), *failed)
|
||||
|
||||
existed, failed, err := SyncLdapUsers(ldap.Owner, LdapUsersToLdapRespUsers(users), ldap.Id)
|
||||
if len(failed) != 0 {
|
||||
logs.Warning(fmt.Sprintf("ldap autosync,%d new users,but %d user failed during :", len(users)-len(existed)-len(failed), len(failed)), failed)
|
||||
logs.Warning(err.Error())
|
||||
} else {
|
||||
logs.Info(fmt.Sprintf("ldap autosync success, %d new users, %d existing users", len(users)-len(*existed), len(*existed)))
|
||||
logs.Info(fmt.Sprintf("ldap autosync success, %d new users, %d existing users", len(users)-len(existed), len(existed)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -259,17 +259,13 @@ func LdapUsersToLdapRespUsers(users []ldapUser) []LdapRespUser {
|
||||
return res
|
||||
}
|
||||
|
||||
func SyncLdapUsers(owner string, respUsers []LdapRespUser, ldapId string) (*[]LdapRespUser, *[]LdapRespUser) {
|
||||
var existUsers []LdapRespUser
|
||||
var failedUsers []LdapRespUser
|
||||
func SyncLdapUsers(owner string, syncUsers []LdapRespUser, ldapId string) (existUsers []LdapRespUser, failedUsers []LdapRespUser, err error) {
|
||||
var uuids []string
|
||||
|
||||
for _, user := range respUsers {
|
||||
for _, user := range syncUsers {
|
||||
uuids = append(uuids, user.Uuid)
|
||||
}
|
||||
|
||||
existUuids := GetExistUuids(owner, uuids)
|
||||
|
||||
organization := getOrganization("admin", owner)
|
||||
ldap := GetLdap(ldapId)
|
||||
|
||||
@@ -289,12 +285,19 @@ func SyncLdapUsers(owner string, respUsers []LdapRespUser, ldapId string) (*[]Ld
|
||||
}
|
||||
tag := strings.Join(ou, ".")
|
||||
|
||||
for _, respUser := range respUsers {
|
||||
for _, syncUser := range syncUsers {
|
||||
if syncUser.Uuid == "" {
|
||||
failedUsers = append(failedUsers, syncUser)
|
||||
err = errors.New("uuid of user being synced is empty")
|
||||
continue
|
||||
}
|
||||
|
||||
existUuids := GetExistUuids(owner, uuids)
|
||||
found := false
|
||||
if len(existUuids) > 0 {
|
||||
for _, existUuid := range existUuids {
|
||||
if respUser.Uuid == existUuid {
|
||||
existUsers = append(existUsers, respUser)
|
||||
if syncUser.Uuid == existUuid {
|
||||
existUsers = append(existUsers, syncUser)
|
||||
found = true
|
||||
}
|
||||
}
|
||||
@@ -303,49 +306,39 @@ func SyncLdapUsers(owner string, respUsers []LdapRespUser, ldapId string) (*[]Ld
|
||||
if !found {
|
||||
newUser := &User{
|
||||
Owner: owner,
|
||||
Name: respUser.buildLdapUserName(),
|
||||
Name: syncUser.buildLdapUserName(),
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
DisplayName: respUser.buildLdapDisplayName(),
|
||||
DisplayName: syncUser.buildLdapDisplayName(),
|
||||
Avatar: organization.DefaultAvatar,
|
||||
Email: respUser.Email,
|
||||
Phone: respUser.Phone,
|
||||
Address: []string{respUser.Address},
|
||||
Email: syncUser.Email,
|
||||
Phone: syncUser.Phone,
|
||||
Address: []string{syncUser.Address},
|
||||
Affiliation: affiliation,
|
||||
Tag: tag,
|
||||
Score: beego.AppConfig.DefaultInt("initScore", 2000),
|
||||
Ldap: respUser.Uuid,
|
||||
Ldap: syncUser.Uuid,
|
||||
}
|
||||
|
||||
affected := AddUser(newUser)
|
||||
if !affected {
|
||||
failedUsers = append(failedUsers, respUser)
|
||||
failedUsers = append(failedUsers, syncUser)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &existUsers, &failedUsers
|
||||
return existUsers, failedUsers, err
|
||||
}
|
||||
|
||||
func GetExistUuids(owner string, uuids []string) []string {
|
||||
var users []User
|
||||
var existUuids []string
|
||||
existUuidSet := make(map[string]struct{})
|
||||
|
||||
err := adapter.Engine.Where(fmt.Sprintf("ldap IN (%s) AND owner = ?", "'"+strings.Join(uuids, "','")+"'"), owner).Find(&users)
|
||||
err := adapter.Engine.Table("user").Where("owner = ?", owner).Cols("ldap").
|
||||
In("ldap", uuids).Select("DISTINCT ldap").Find(&existUuids)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if len(users) > 0 {
|
||||
for _, result := range users {
|
||||
existUuidSet[result.Ldap] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
for uuid := range existUuidSet {
|
||||
existUuids = append(existUuids, uuid)
|
||||
}
|
||||
return existUuids
|
||||
}
|
||||
|
||||
|
@@ -235,6 +235,16 @@ func GetPermissionsByRole(roleId string) []*Permission {
|
||||
return permissions
|
||||
}
|
||||
|
||||
func GetPermissionsByResource(resourceId string) []*Permission {
|
||||
permissions := []*Permission{}
|
||||
err := adapter.Engine.Where("resources like ?", "%"+resourceId+"\"%").Find(&permissions)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return permissions
|
||||
}
|
||||
|
||||
func GetPermissionsBySubmitter(owner string, submitter string) []*Permission {
|
||||
permissions := []*Permission{}
|
||||
err := adapter.Engine.Desc("created_time").Find(&permissions, &Permission{Owner: owner, Submitter: submitter})
|
||||
|
@@ -47,7 +47,8 @@ type Record struct {
|
||||
RequestUri string `xorm:"varchar(1000)" json:"requestUri"`
|
||||
Action string `xorm:"varchar(1000)" json:"action"`
|
||||
|
||||
ExtendedUser *User `xorm:"-" json:"extendedUser"`
|
||||
Object string `xorm:"-" json:"object"`
|
||||
ExtendedUser *User `xorm:"-" json:"extendedUser"`
|
||||
|
||||
IsTriggered bool `json:"isTriggered"`
|
||||
}
|
||||
@@ -60,6 +61,11 @@ func NewRecord(ctx *context.Context) *Record {
|
||||
requestUri = requestUri[0:1000]
|
||||
}
|
||||
|
||||
object := ""
|
||||
if ctx.Input.RequestBody != nil && len(ctx.Input.RequestBody) != 0 {
|
||||
object = string(ctx.Input.RequestBody)
|
||||
}
|
||||
|
||||
record := Record{
|
||||
Name: util.GenerateId(),
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
@@ -68,6 +74,7 @@ func NewRecord(ctx *context.Context) *Record {
|
||||
Method: ctx.Request.Method,
|
||||
RequestUri: requestUri,
|
||||
Action: action,
|
||||
Object: object,
|
||||
IsTriggered: false,
|
||||
}
|
||||
return &record
|
||||
@@ -159,7 +166,7 @@ func SendWebhooks(record *Record) error {
|
||||
|
||||
if matched {
|
||||
if webhook.IsUserExtended {
|
||||
user := getUser(record.Organization, record.User)
|
||||
user := GetMaskedUser(getUser(record.Organization, record.User))
|
||||
record.ExtendedUser = user
|
||||
}
|
||||
|
||||
|
@@ -224,6 +224,9 @@ func generateJwtToken(application *Application, user *User, nonce string, scope
|
||||
nowTime := time.Now()
|
||||
expireTime := nowTime.Add(time.Duration(application.ExpireInHours) * time.Hour)
|
||||
refreshExpireTime := nowTime.Add(time.Duration(application.RefreshExpireInHours) * time.Hour)
|
||||
if application.RefreshExpireInHours == 0 {
|
||||
refreshExpireTime = expireTime
|
||||
}
|
||||
|
||||
user = refineUser(user)
|
||||
|
||||
|
@@ -472,6 +472,13 @@ func UpdateUser(id string, user *User, columns []string, isAdmin bool) bool {
|
||||
"location", "address", "country_code", "region", "language", "affiliation", "title", "homepage", "bio", "tag", "language", "gender", "birthday", "education", "score", "karma", "ranking", "signup_application",
|
||||
"is_admin", "is_global_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials", "managedAccounts",
|
||||
"signin_wrong_times", "last_signin_wrong_time",
|
||||
"github", "google", "qq", "wechat", "facebook", "dingtalk", "weibo", "gitee", "linkedin", "wecom", "lark", "gitlab", "adfs",
|
||||
"baidu", "alipay", "casdoor", "infoflow", "apple", "azuread", "slack", "steam", "bilibili", "okta", "douyin", "line", "amazon",
|
||||
"auth0", "battlenet", "bitbucket", "box", "cloudfoundry", "dailymotion", "deezer", "digitalocean", "discord", "dropbox",
|
||||
"eveonline", "fitbit", "gitea", "heroku", "influxcloud", "instagram", "intercom", "kakao", "lastfm", "mailru", "meetup",
|
||||
"microsoftonline", "naver", "nextcloud", "onedrive", "oura", "patreon", "paypal", "salesforce", "shopify", "soundcloud",
|
||||
"spotify", "strava", "stripe", "tiktok", "tumblr", "twitch", "twitter", "typetalk", "uber", "vk", "wepay", "xero", "yahoo",
|
||||
"yammer", "yandex", "zoom", "custom",
|
||||
}
|
||||
}
|
||||
if isAdmin {
|
||||
|
@@ -550,7 +550,7 @@ class App extends Component {
|
||||
<Route exact path="/syncers" render={(props) => this.renderLoginIfNotLoggedIn(<SyncerListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/syncers/:syncerName" render={(props) => this.renderLoginIfNotLoggedIn(<SyncerEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/certs" render={(props) => this.renderLoginIfNotLoggedIn(<CertListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/certs/:certName" render={(props) => this.renderLoginIfNotLoggedIn(<CertEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/certs/:organizationName/:certName" render={(props) => this.renderLoginIfNotLoggedIn(<CertEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/chats" render={(props) => this.renderLoginIfNotLoggedIn(<ChatListPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/chats/:chatName" render={(props) => this.renderLoginIfNotLoggedIn(<ChatEditPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/chat" render={(props) => this.renderLoginIfNotLoggedIn(<ChatPage account={this.state.account} {...props} />)} />
|
||||
|
@@ -112,7 +112,6 @@ class ApplicationEditPage extends React.Component {
|
||||
UNSAFE_componentWillMount() {
|
||||
this.getApplication();
|
||||
this.getOrganizations();
|
||||
this.getCerts();
|
||||
this.getProviders();
|
||||
this.getSamlMetadata();
|
||||
}
|
||||
@@ -126,6 +125,8 @@ class ApplicationEditPage extends React.Component {
|
||||
this.setState({
|
||||
application: application,
|
||||
});
|
||||
|
||||
this.getCerts(application.organization);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -144,8 +145,8 @@ class ApplicationEditPage extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
getCerts() {
|
||||
CertBackend.getCerts(this.props.account.owner)
|
||||
getCerts(owner) {
|
||||
CertBackend.getCerts(owner)
|
||||
.then((res) => {
|
||||
this.setState({
|
||||
certs: (res.msg === undefined) ? res : [],
|
||||
|
@@ -65,6 +65,7 @@ class ApplicationListPage extends BaseListPage {
|
||||
redirectUris: ["http://localhost:9000/callback"],
|
||||
tokenFormat: "JWT",
|
||||
expireInHours: 24 * 7,
|
||||
refreshExpireInHours: 24 * 7,
|
||||
formOffset: 2,
|
||||
};
|
||||
}
|
||||
|
@@ -15,6 +15,7 @@
|
||||
import React from "react";
|
||||
import {Button, Card, Col, Input, InputNumber, Row, Select} from "antd";
|
||||
import * as CertBackend from "./backend/CertBackend";
|
||||
import * as OrganizationBackend from "./backend/OrganizationBackend";
|
||||
import * as Setting from "./Setting";
|
||||
import i18next from "i18next";
|
||||
import copy from "copy-to-clipboard";
|
||||
@@ -29,6 +30,7 @@ class CertEditPage extends React.Component {
|
||||
this.state = {
|
||||
classes: props,
|
||||
certName: props.match.params.certName,
|
||||
owner: props.match.params.organizationName,
|
||||
cert: null,
|
||||
organizations: [],
|
||||
mode: props.location.mode !== undefined ? props.location.mode : "edit",
|
||||
@@ -37,10 +39,11 @@ class CertEditPage extends React.Component {
|
||||
|
||||
UNSAFE_componentWillMount() {
|
||||
this.getCert();
|
||||
this.getOrganizations();
|
||||
}
|
||||
|
||||
getCert() {
|
||||
CertBackend.getCert(this.props.account.owner, this.state.certName)
|
||||
CertBackend.getCert(this.state.owner, this.state.certName)
|
||||
.then((cert) => {
|
||||
this.setState({
|
||||
cert: cert,
|
||||
@@ -48,6 +51,15 @@ class CertEditPage extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
getOrganizations() {
|
||||
OrganizationBackend.getOrganizations("admin")
|
||||
.then((res) => {
|
||||
this.setState({
|
||||
organizations: (res.msg === undefined) ? res : [],
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
parseCertField(key, value) {
|
||||
if (["port"].includes(key)) {
|
||||
value = Setting.myParseInt(value);
|
||||
@@ -230,7 +242,7 @@ class CertEditPage extends React.Component {
|
||||
|
||||
submitCertEdit(willExist) {
|
||||
const cert = Setting.deepCopy(this.state.cert);
|
||||
CertBackend.updateCert(this.state.cert.owner, this.state.certName, cert)
|
||||
CertBackend.updateCert(this.state.owner, this.state.certName, cert)
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
Setting.showMessage("success", i18next.t("general:Successfully saved"));
|
||||
@@ -241,7 +253,7 @@ class CertEditPage extends React.Component {
|
||||
if (willExist) {
|
||||
this.props.history.push("/certs");
|
||||
} else {
|
||||
this.props.history.push(`/certs/${this.state.cert.name}`);
|
||||
this.props.history.push(`/certs/${this.state.cert.owner}/${this.state.cert.name}`);
|
||||
}
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to save")}: ${res.msg}`);
|
||||
|
@@ -23,10 +23,20 @@ import BaseListPage from "./BaseListPage";
|
||||
import PopconfirmModal from "./common/modal/PopconfirmModal";
|
||||
|
||||
class CertListPage extends BaseListPage {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.setState({
|
||||
owner: Setting.isAdminUser(this.props.account) ? "admin" : this.props.account.owner,
|
||||
});
|
||||
}
|
||||
|
||||
newCert() {
|
||||
const randomName = Setting.getRandomName();
|
||||
return {
|
||||
owner: this.props.account.owner, // this.props.account.certname,
|
||||
owner: this.state.owner,
|
||||
name: `cert_${randomName}`,
|
||||
createdTime: moment().format(),
|
||||
displayName: `New Cert - ${randomName}`,
|
||||
@@ -45,7 +55,7 @@ class CertListPage extends BaseListPage {
|
||||
CertBackend.addCert(newCert)
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.props.history.push({pathname: `/certs/${newCert.name}`, mode: "add"});
|
||||
this.props.history.push({pathname: `/certs/${newCert.owner}/${newCert.name}`, mode: "add"});
|
||||
Setting.showMessage("success", i18next.t("general:Successfully added"));
|
||||
} else {
|
||||
Setting.showMessage("error", `${i18next.t("general:Failed to add")}: ${res.msg}`);
|
||||
@@ -86,7 +96,7 @@ class CertListPage extends BaseListPage {
|
||||
...this.getColumnSearchProps("name"),
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Link to={`/certs/${text}`}>
|
||||
<Link to={`/certs/${record.owner}/${text}`}>
|
||||
{text}
|
||||
</Link>
|
||||
);
|
||||
@@ -99,6 +109,9 @@ class CertListPage extends BaseListPage {
|
||||
width: "150px",
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps("organization"),
|
||||
render: (text, record, index) => {
|
||||
return (text !== "admin") ? text : i18next.t("provider:admin (Shared)");
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Created time"),
|
||||
@@ -176,7 +189,7 @@ class CertListPage extends BaseListPage {
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<div>
|
||||
<Button disabled={!Setting.isAdminUser(this.props.account) && (record.owner !== this.props.account.owner)} style={{marginTop: "10px", marginBottom: "10px", marginRight: "10px"}} type="primary" onClick={() => this.props.history.push(`/certs/${record.name}`)}>{i18next.t("general:Edit")}</Button>
|
||||
<Button disabled={!Setting.isAdminUser(this.props.account) && (record.owner !== this.props.account.owner)} style={{marginTop: "10px", marginBottom: "10px", marginRight: "10px"}} type="primary" onClick={() => this.props.history.push(`/certs/${record.owner}/${record.name}`)}>{i18next.t("general:Edit")}</Button>
|
||||
<PopconfirmModal
|
||||
disabled={!Setting.isAdminUser(this.props.account) && (record.owner !== this.props.account.owner)}
|
||||
title={i18next.t("general:Sure to delete") + `: ${record.name} ?`}
|
||||
|
@@ -94,7 +94,7 @@ class LdapSyncPage extends React.Component {
|
||||
if (res.status === "ok") {
|
||||
this.setState((prevState) => {
|
||||
prevState.users = res.data.users;
|
||||
prevState.existUuids = res.data2?.length > 0 ? res.data2 : [];
|
||||
prevState.existUuids = res.data2?.length > 0 ? res.data2.filter(uuid => uuid !== "") : [];
|
||||
return prevState;
|
||||
});
|
||||
} else {
|
||||
@@ -210,7 +210,7 @@ class LdapSyncPage extends React.Component {
|
||||
});
|
||||
},
|
||||
getCheckboxProps: record => ({
|
||||
disabled: this.state.existUuids.indexOf(record.uuid) !== -1,
|
||||
disabled: this.state.existUuids.indexOf(record.uuid) !== -1 || record.uidNumber === "",
|
||||
}),
|
||||
};
|
||||
|
||||
|
@@ -200,6 +200,22 @@ class OrganizationEditPage extends React.Component {
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Languages"), i18next.t("general:Languages - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} mode="tags" style={{width: "100%"}}
|
||||
options={Setting.Countries.map((item) => {
|
||||
return Setting.getOption(item.label, item.key);
|
||||
})}
|
||||
value={this.state.organization.languages ?? []}
|
||||
onChange={(value => {
|
||||
this.updateOrganizationField("languages", value);
|
||||
})} >
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Default avatar"), i18next.t("general:Default avatar - Tooltip"))} :
|
||||
@@ -259,22 +275,6 @@ class OrganizationEditPage extends React.Component {
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Languages"), i18next.t("general:Languages - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Select virtual={false} mode="tags" style={{width: "100%"}}
|
||||
options={Setting.Countries.map((item) => {
|
||||
return Setting.getOption(item.label, item.key);
|
||||
})}
|
||||
value={this.state.organization.languages ?? []}
|
||||
onChange={(value => {
|
||||
this.updateOrganizationField("languages", value);
|
||||
})} >
|
||||
</Select>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||
{Setting.getLabel(i18next.t("organization:Init score"), i18next.t("organization:Init score - Tooltip"))} :
|
||||
|
@@ -112,6 +112,9 @@ class ProviderListPage extends BaseListPage {
|
||||
width: "150px",
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps("organization"),
|
||||
render: (text, record, index) => {
|
||||
return (text !== "admin") ? text : i18next.t("provider:admin (Shared)");
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Created time"),
|
||||
|
@@ -28,6 +28,20 @@ require("codemirror/mode/javascript/javascript");
|
||||
|
||||
const {Option} = Select;
|
||||
|
||||
const applicationTemplate = {
|
||||
owner: "admin", // this.props.account.applicationName,
|
||||
name: "application_123",
|
||||
organization: "built-in",
|
||||
createdTime: "2022-01-01T01:03:42+08:00",
|
||||
displayName: "New Application - 123",
|
||||
logo: `${Setting.StaticBaseUrl}/img/casdoor-logo_1185x256.png`,
|
||||
enablePassword: true,
|
||||
enableSignUp: true,
|
||||
enableSigninSession: false,
|
||||
enableCodeSignin: false,
|
||||
enableSamlCompress: false,
|
||||
};
|
||||
|
||||
const previewTemplate = {
|
||||
"id": 9078,
|
||||
"owner": "built-in",
|
||||
@@ -37,9 +51,10 @@ const previewTemplate = {
|
||||
"clientIp": "159.89.126.192",
|
||||
"user": "admin",
|
||||
"method": "POST",
|
||||
"requestUri": "/api/login",
|
||||
"requestUri": "/api/add-application",
|
||||
"action": "login",
|
||||
"isTriggered": false,
|
||||
"object": JSON.stringify(applicationTemplate),
|
||||
};
|
||||
|
||||
const userTemplate = {
|
||||
@@ -49,7 +64,7 @@ const userTemplate = {
|
||||
"updatedTime": "",
|
||||
"id": "9eb20f79-3bb5-4e74-99ac-39e3b9a171e8",
|
||||
"type": "normal-user",
|
||||
"password": "123",
|
||||
"password": "***",
|
||||
"passwordSalt": "",
|
||||
"displayName": "Admin",
|
||||
"avatar": "https://cdn.casbin.com/usercontent/admin/avatar/1596241359.png",
|
||||
|
@@ -242,6 +242,7 @@ class LoginPage extends React.Component {
|
||||
|
||||
if (resp.msg === RequiredMfa) {
|
||||
Setting.goToLink(`/prompt/${application.name}?redirectUri=${oAuthParams.redirectUri}&code=${code}&state=${oAuthParams.state}&promptType=mfa`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Setting.isPromptAnswered(account, application)) {
|
||||
|
Reference in New Issue
Block a user