mirror of
https://github.com/casdoor/casdoor.git
synced 2025-08-22 04:10:32 +08:00
Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a147fa3e0b | ||
![]() |
9d03665523 | ||
![]() |
0106c7f7fa | ||
![]() |
6713dad0af | ||
![]() |
6ef2b51782 | ||
![]() |
1732cd8538 | ||
![]() |
a10548fe73 | ||
![]() |
f6a7888f83 | ||
![]() |
93efaa5459 | ||
![]() |
0bfe683108 | ||
![]() |
8a4758c22d | ||
![]() |
ee3b46e91c | ||
![]() |
37744d6cd7 | ||
![]() |
98defe617b | ||
![]() |
96cbf51ca0 | ||
![]() |
22b57fdd23 | ||
![]() |
b68e291f37 | ||
![]() |
9960b4933b |
@@ -127,8 +127,14 @@ func IsAllowed(subOwner string, subName string, method string, urlPath string, o
|
||||
return true
|
||||
}
|
||||
|
||||
if user != nil && user.IsAdmin && (subOwner == objOwner || (objOwner == "admin")) {
|
||||
return true
|
||||
if user != nil {
|
||||
if user.IsDeleted {
|
||||
return false
|
||||
}
|
||||
|
||||
if user.IsAdmin && (subOwner == objOwner || (objOwner == "admin")) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
res, err := Enforcer.Enforce(subOwner, subName, method, urlPath, objOwner, objName)
|
||||
|
@@ -477,11 +477,10 @@ func (c *ApiController) Login() {
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:The provider: %s is not enabled for the application"), provider.Name))
|
||||
return
|
||||
}
|
||||
|
||||
userInfo := &idp.UserInfo{}
|
||||
if provider.Category == "SAML" {
|
||||
// SAML
|
||||
userInfo.Id, err = object.ParseSamlResponse(authForm.SamlResponse, provider, c.Ctx.Request.Host)
|
||||
userInfo, err = object.ParseSamlResponse(authForm.SamlResponse, provider, c.Ctx.Request.Host)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
@@ -524,7 +523,8 @@ func (c *ApiController) Login() {
|
||||
if authForm.Method == "signup" {
|
||||
user := &object.User{}
|
||||
if provider.Category == "SAML" {
|
||||
user, err = object.GetUser(util.GetId(application.Organization, userInfo.Id))
|
||||
// The userInfo.Id is the NameID in SAML response, it could be name / email / phone
|
||||
user, err = object.GetUserByFields(application.Organization, userInfo.Id)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
@@ -651,6 +651,15 @@ func (c *ApiController) Login() {
|
||||
c.ResponseError(fmt.Sprintf(c.T("auth:Failed to create user, user information is invalid: %s"), util.StructToJson(user)))
|
||||
return
|
||||
}
|
||||
|
||||
if providerItem.SignupGroup != "" {
|
||||
user.Groups = []string{providerItem.SignupGroup}
|
||||
_, err = object.UpdateUser(user.GetId(), user, []string{"groups"}, false)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sync info from 3rd-party if possible
|
||||
@@ -679,6 +688,7 @@ func (c *ApiController) Login() {
|
||||
record2.User = user.Name
|
||||
util.SafeGoroutine(func() { object.AddRecord(record2) })
|
||||
} else if provider.Category == "SAML" {
|
||||
// TODO: since we get the user info from SAML response, we can try to create the user
|
||||
resp = &Response{Status: "error", Msg: fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(application.Organization, userInfo.Id))}
|
||||
}
|
||||
// resp = &Response{Status: "ok", Msg: "", Data: res}
|
||||
|
@@ -85,7 +85,7 @@ func GetIdProvider(idpInfo *ProviderInfo, redirectUrl string) IdProvider {
|
||||
return NewLarkIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl)
|
||||
case "GitLab":
|
||||
return NewGitlabIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl)
|
||||
case "Adfs":
|
||||
case "ADFS":
|
||||
return NewAdfsIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl, idpInfo.HostUrl)
|
||||
case "Baidu":
|
||||
return NewBaiduIdProvider(idpInfo.ClientId, idpInfo.ClientSecret, redirectUrl)
|
||||
|
@@ -57,6 +57,7 @@ type Application struct {
|
||||
EnableAutoSignin bool `json:"enableAutoSignin"`
|
||||
EnableCodeSignin bool `json:"enableCodeSignin"`
|
||||
EnableSamlCompress bool `json:"enableSamlCompress"`
|
||||
EnableSamlC14n10 bool `json:"enableSamlC14n10"`
|
||||
EnableWebAuthn bool `json:"enableWebAuthn"`
|
||||
EnableLinkWithEmail bool `json:"enableLinkWithEmail"`
|
||||
OrgChoiceMode string `json:"orgChoiceMode"`
|
||||
|
@@ -379,7 +379,10 @@ func CheckLoginPermission(userId string, application *Application) (bool, error)
|
||||
continue
|
||||
}
|
||||
|
||||
enforcer := getPermissionEnforcer(permission)
|
||||
enforcer, err := getPermissionEnforcer(permission)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
var isAllowed bool
|
||||
isAllowed, err = enforcer.Enforce(userId, application.Name, "Read")
|
||||
|
@@ -178,7 +178,7 @@ func initBuiltInApplication() {
|
||||
EnablePassword: true,
|
||||
EnableSignUp: true,
|
||||
Providers: []*ProviderItem{
|
||||
{Name: "provider_captcha_default", CanSignUp: false, CanSignIn: false, CanUnlink: false, Prompted: false, AlertType: "None", Rule: "None", Provider: nil},
|
||||
{Name: "provider_captcha_default", CanSignUp: false, CanSignIn: false, CanUnlink: false, Prompted: false, SignupGroup: "", Rule: "None", Provider: nil},
|
||||
},
|
||||
SignupItems: []*SignupItem{
|
||||
{Name: "ID", Visible: false, Required: true, Prompted: false, Rule: "Random"},
|
||||
|
@@ -113,11 +113,15 @@ func GetPermission(id string) (*Permission, error) {
|
||||
|
||||
// checkPermissionValid verifies if the permission is valid
|
||||
func checkPermissionValid(permission *Permission) error {
|
||||
enforcer := getPermissionEnforcer(permission)
|
||||
enforcer, err := getPermissionEnforcer(permission)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
enforcer.EnableAutoSave(false)
|
||||
|
||||
policies := getPolicies(permission)
|
||||
_, err := enforcer.AddPolicies(policies)
|
||||
_, err = enforcer.AddPolicies(policies)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -129,7 +133,7 @@ func checkPermissionValid(permission *Permission) error {
|
||||
|
||||
groupingPolicies := getGroupingPolicies(permission)
|
||||
if len(groupingPolicies) > 0 {
|
||||
_, err := enforcer.AddGroupingPolicies(groupingPolicies)
|
||||
_, err = enforcer.AddGroupingPolicies(groupingPolicies)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -150,7 +154,7 @@ func UpdatePermission(id string, permission *Permission) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if permission.ResourceType == "Application" {
|
||||
if permission.ResourceType == "Application" && permission.Model != "" {
|
||||
model, err := GetModelEx(util.GetId(owner, permission.Model))
|
||||
if err != nil {
|
||||
return false, err
|
||||
@@ -174,8 +178,16 @@ func UpdatePermission(id string, permission *Permission) (bool, error) {
|
||||
}
|
||||
|
||||
if affected != 0 {
|
||||
removeGroupingPolicies(oldPermission)
|
||||
removePolicies(oldPermission)
|
||||
err = removeGroupingPolicies(oldPermission)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
err = removePolicies(oldPermission)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if oldPermission.Adapter != "" && oldPermission.Adapter != permission.Adapter {
|
||||
isEmpty, _ := ormer.Engine.IsTableEmpty(oldPermission.Adapter)
|
||||
if isEmpty {
|
||||
@@ -185,8 +197,16 @@ func UpdatePermission(id string, permission *Permission) (bool, error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
addGroupingPolicies(permission)
|
||||
addPolicies(permission)
|
||||
|
||||
err = addGroupingPolicies(permission)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
err = addPolicies(permission)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
return affected != 0, nil
|
||||
@@ -199,40 +219,54 @@ func AddPermission(permission *Permission) (bool, error) {
|
||||
}
|
||||
|
||||
if affected != 0 {
|
||||
addGroupingPolicies(permission)
|
||||
addPolicies(permission)
|
||||
err = addGroupingPolicies(permission)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
err = addPolicies(permission)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
return affected != 0, nil
|
||||
}
|
||||
|
||||
func AddPermissions(permissions []*Permission) bool {
|
||||
func AddPermissions(permissions []*Permission) (bool, error) {
|
||||
if len(permissions) == 0 {
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
affected, err := ormer.Engine.Insert(permissions)
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "Duplicate entry") {
|
||||
panic(err)
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, permission := range permissions {
|
||||
// add using for loop
|
||||
if affected != 0 {
|
||||
addGroupingPolicies(permission)
|
||||
addPolicies(permission)
|
||||
err = addGroupingPolicies(permission)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
err = addPolicies(permission)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return affected != 0
|
||||
return affected != 0, nil
|
||||
}
|
||||
|
||||
func AddPermissionsInBatch(permissions []*Permission) bool {
|
||||
func AddPermissionsInBatch(permissions []*Permission) (bool, error) {
|
||||
batchSize := conf.GetConfigBatchSize()
|
||||
|
||||
if len(permissions) == 0 {
|
||||
return false
|
||||
return false, nil
|
||||
}
|
||||
|
||||
affected := false
|
||||
@@ -245,12 +279,18 @@ func AddPermissionsInBatch(permissions []*Permission) bool {
|
||||
|
||||
tmp := permissions[start:end]
|
||||
fmt.Printf("The syncer adds permissions: [%d - %d]\n", start, end)
|
||||
if AddPermissions(tmp) {
|
||||
|
||||
b, err := AddPermissions(tmp)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if b {
|
||||
affected = true
|
||||
}
|
||||
}
|
||||
|
||||
return affected
|
||||
return affected, nil
|
||||
}
|
||||
|
||||
func DeletePermission(permission *Permission) (bool, error) {
|
||||
@@ -260,8 +300,16 @@ func DeletePermission(permission *Permission) (bool, error) {
|
||||
}
|
||||
|
||||
if affected != 0 {
|
||||
removeGroupingPolicies(permission)
|
||||
removePolicies(permission)
|
||||
err = removeGroupingPolicies(permission)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
err = removePolicies(permission)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if permission.Adapter != "" && permission.Adapter != "permission_rule" {
|
||||
isEmpty, _ := ormer.Engine.IsTableEmpty(permission.Adapter)
|
||||
if isEmpty {
|
||||
|
@@ -26,23 +26,23 @@ import (
|
||||
xormadapter "github.com/casdoor/xorm-adapter/v3"
|
||||
)
|
||||
|
||||
func getPermissionEnforcer(p *Permission, permissionIDs ...string) *casbin.Enforcer {
|
||||
func getPermissionEnforcer(p *Permission, permissionIDs ...string) (*casbin.Enforcer, error) {
|
||||
// Init an enforcer instance without specifying a model or adapter.
|
||||
// If you specify an adapter, it will load all policies, which is a
|
||||
// heavy process that can slow down the application.
|
||||
enforcer, err := casbin.NewEnforcer(&log.DefaultLogger{}, false)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = p.setEnforcerModel(enforcer)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = p.setEnforcerAdapter(enforcer)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
policyFilterV5 := []string{p.GetId()}
|
||||
@@ -60,10 +60,10 @@ func getPermissionEnforcer(p *Permission, permissionIDs ...string) *casbin.Enfor
|
||||
|
||||
err = enforcer.LoadFilteredPolicy(policyFilter)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return enforcer
|
||||
return enforcer, nil
|
||||
}
|
||||
|
||||
func (p *Permission) setEnforcerAdapter(enforcer *casbin.Enforcer) error {
|
||||
@@ -201,72 +201,96 @@ func getGroupingPolicies(permission *Permission) [][]string {
|
||||
return groupingPolicies
|
||||
}
|
||||
|
||||
func addPolicies(permission *Permission) {
|
||||
enforcer := getPermissionEnforcer(permission)
|
||||
func addPolicies(permission *Permission) error {
|
||||
enforcer, err := getPermissionEnforcer(permission)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
policies := getPolicies(permission)
|
||||
|
||||
_, err := enforcer.AddPolicies(policies)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, err = enforcer.AddPolicies(policies)
|
||||
return err
|
||||
}
|
||||
|
||||
func addGroupingPolicies(permission *Permission) {
|
||||
enforcer := getPermissionEnforcer(permission)
|
||||
func removePolicies(permission *Permission) error {
|
||||
enforcer, err := getPermissionEnforcer(permission)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
policies := getPolicies(permission)
|
||||
|
||||
_, err = enforcer.RemovePolicies(policies)
|
||||
return err
|
||||
}
|
||||
|
||||
func addGroupingPolicies(permission *Permission) error {
|
||||
enforcer, err := getPermissionEnforcer(permission)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
groupingPolicies := getGroupingPolicies(permission)
|
||||
|
||||
if len(groupingPolicies) > 0 {
|
||||
_, err := enforcer.AddGroupingPolicies(groupingPolicies)
|
||||
_, err = enforcer.AddGroupingPolicies(groupingPolicies)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func removeGroupingPolicies(permission *Permission) {
|
||||
enforcer := getPermissionEnforcer(permission)
|
||||
func removeGroupingPolicies(permission *Permission) error {
|
||||
enforcer, err := getPermissionEnforcer(permission)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
groupingPolicies := getGroupingPolicies(permission)
|
||||
|
||||
if len(groupingPolicies) > 0 {
|
||||
_, err := enforcer.RemoveGroupingPolicies(groupingPolicies)
|
||||
_, err = enforcer.RemoveGroupingPolicies(groupingPolicies)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func removePolicies(permission *Permission) {
|
||||
enforcer := getPermissionEnforcer(permission)
|
||||
policies := getPolicies(permission)
|
||||
|
||||
_, err := enforcer.RemovePolicies(policies)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type CasbinRequest = []interface{}
|
||||
|
||||
func Enforce(permission *Permission, request *CasbinRequest, permissionIds ...string) (bool, error) {
|
||||
enforcer := getPermissionEnforcer(permission, permissionIds...)
|
||||
enforcer, err := getPermissionEnforcer(permission, permissionIds...)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return enforcer.Enforce(*request...)
|
||||
}
|
||||
|
||||
func BatchEnforce(permission *Permission, requests *[]CasbinRequest, permissionIds ...string) ([]bool, error) {
|
||||
enforcer := getPermissionEnforcer(permission, permissionIds...)
|
||||
enforcer, err := getPermissionEnforcer(permission, permissionIds...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return enforcer.BatchEnforce(*requests)
|
||||
}
|
||||
|
||||
func getAllValues(userId string, fn func(enforcer *casbin.Enforcer) []string) []string {
|
||||
func getAllValues(userId string, fn func(enforcer *casbin.Enforcer) []string) ([]string, error) {
|
||||
permissions, _, err := getPermissionsAndRolesByUser(userId)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, role := range GetAllRoles(userId) {
|
||||
permissionsByRole, err := GetPermissionsByRole(role)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
permissions = append(permissions, permissionsByRole...)
|
||||
@@ -274,19 +298,24 @@ func getAllValues(userId string, fn func(enforcer *casbin.Enforcer) []string) []
|
||||
|
||||
var values []string
|
||||
for _, permission := range permissions {
|
||||
enforcer := getPermissionEnforcer(permission)
|
||||
enforcer, err := getPermissionEnforcer(permission)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
values = append(values, fn(enforcer)...)
|
||||
}
|
||||
return values
|
||||
|
||||
return values, nil
|
||||
}
|
||||
|
||||
func GetAllObjects(userId string) []string {
|
||||
func GetAllObjects(userId string) ([]string, error) {
|
||||
return getAllValues(userId, func(enforcer *casbin.Enforcer) []string {
|
||||
return enforcer.GetAllObjects()
|
||||
})
|
||||
}
|
||||
|
||||
func GetAllActions(userId string) []string {
|
||||
func GetAllActions(userId string) ([]string, error) {
|
||||
return getAllValues(userId, func(enforcer *casbin.Enforcer) []string {
|
||||
return enforcer.GetAllActions()
|
||||
})
|
||||
@@ -330,17 +359,23 @@ m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act`
|
||||
|
||||
// load [policy_definition]
|
||||
policyDefinition := strings.Split(cfg.String("policy_definition::p"), ",")
|
||||
|
||||
fieldsNum := len(policyDefinition)
|
||||
if fieldsNum > builtInAvailableField {
|
||||
panic(fmt.Errorf("the maximum policy_definition field number cannot exceed %d, got %d", builtInAvailableField, fieldsNum))
|
||||
return nil, fmt.Errorf("the maximum policy_definition field number cannot exceed %d, got %d", builtInAvailableField, fieldsNum)
|
||||
}
|
||||
|
||||
// filled empty field with "" and V5 with "permissionId"
|
||||
for i := builtInAvailableField - fieldsNum; i > 0; i-- {
|
||||
policyDefinition = append(policyDefinition, "")
|
||||
}
|
||||
policyDefinition = append(policyDefinition, "permissionId")
|
||||
|
||||
m, _ := model.NewModelFromString(modelText)
|
||||
m, err := model.NewModelFromString(modelText)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m.AddDef("p", "p", strings.Join(policyDefinition, ","))
|
||||
|
||||
return m, err
|
||||
|
@@ -83,5 +83,10 @@ func UploadPermissions(owner string, path string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return AddPermissionsInBatch(newPermissions), nil
|
||||
affected, err := AddPermissionsInBatch(newPermissions)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return affected, nil
|
||||
}
|
||||
|
@@ -415,7 +415,7 @@ func FromProviderToIdpInfo(ctx *context.Context, provider *Provider) *idp.Provid
|
||||
providerInfo.ClientId = provider.ClientId2
|
||||
providerInfo.ClientSecret = provider.ClientSecret2
|
||||
}
|
||||
} else if provider.Type == "AzureAD" {
|
||||
} else if provider.Type == "AzureAD" || provider.Type == "ADFS" {
|
||||
providerInfo.HostUrl = provider.Domain
|
||||
}
|
||||
|
||||
|
@@ -18,13 +18,13 @@ type ProviderItem struct {
|
||||
Owner string `json:"owner"`
|
||||
Name string `json:"name"`
|
||||
|
||||
CanSignUp bool `json:"canSignUp"`
|
||||
CanSignIn bool `json:"canSignIn"`
|
||||
CanUnlink bool `json:"canUnlink"`
|
||||
Prompted bool `json:"prompted"`
|
||||
AlertType string `json:"alertType"`
|
||||
Rule string `json:"rule"`
|
||||
Provider *Provider `json:"provider"`
|
||||
CanSignUp bool `json:"canSignUp"`
|
||||
CanSignIn bool `json:"canSignIn"`
|
||||
CanUnlink bool `json:"canUnlink"`
|
||||
Prompted bool `json:"prompted"`
|
||||
SignupGroup string `json:"signupGroup"`
|
||||
Rule string `json:"rule"`
|
||||
Provider *Provider `json:"provider"`
|
||||
}
|
||||
|
||||
func (application *Application) GetProviderItem(providerName string) *ProviderItem {
|
||||
|
@@ -151,8 +151,16 @@ func UpdateRole(id string, role *Role) (bool, error) {
|
||||
}
|
||||
|
||||
for _, permission := range permissions {
|
||||
addGroupingPolicies(permission)
|
||||
addPolicies(permission)
|
||||
err = addGroupingPolicies(permission)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
err = addPolicies(permission)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
visited[permission.GetId()] = struct{}{}
|
||||
}
|
||||
|
||||
@@ -166,10 +174,15 @@ func UpdateRole(id string, role *Role) (bool, error) {
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
for _, permission := range permissions {
|
||||
permissionId := permission.GetId()
|
||||
if _, ok := visited[permissionId]; !ok {
|
||||
addGroupingPolicies(permission)
|
||||
err = addGroupingPolicies(permission)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
visited[permissionId] = struct{}{}
|
||||
}
|
||||
}
|
||||
@@ -259,9 +272,9 @@ func getRolesByUserInternal(userId string) ([]*Role, error) {
|
||||
return roles, err
|
||||
}
|
||||
|
||||
query := ormer.Engine.Where("role.users like ?", fmt.Sprintf("%%%s%%", userId))
|
||||
query := ormer.Engine.Where("users like ?", fmt.Sprintf("%%%s%%", userId))
|
||||
for _, group := range user.Groups {
|
||||
query = query.Or("role.groups like ?", fmt.Sprintf("%%%s%%", group))
|
||||
query = query.Or("groups like ?", fmt.Sprintf("%%%s%%", group))
|
||||
}
|
||||
|
||||
err = query.Find(&roles)
|
||||
|
@@ -324,6 +324,11 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
|
||||
}
|
||||
ctx := dsig.NewDefaultSigningContext(randomKeyStore)
|
||||
ctx.Hash = crypto.SHA1
|
||||
|
||||
if application.EnableSamlC14n10 {
|
||||
ctx.Canonicalizer = dsig.MakeC14N10ExclusiveCanonicalizerWithPrefixList("")
|
||||
}
|
||||
|
||||
//signedXML, err := ctx.SignEnvelopedLimix(samlResponse)
|
||||
//if err != nil {
|
||||
// return "", "", fmt.Errorf("err: %s", err.Error())
|
||||
|
@@ -23,23 +23,49 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/casdoor/casdoor/idp"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
|
||||
"github.com/casdoor/casdoor/i18n"
|
||||
saml2 "github.com/russellhaering/gosaml2"
|
||||
dsig "github.com/russellhaering/goxmldsig"
|
||||
)
|
||||
|
||||
func ParseSamlResponse(samlResponse string, provider *Provider, host string) (string, error) {
|
||||
func ParseSamlResponse(samlResponse string, provider *Provider, host string) (*idp.UserInfo, error) {
|
||||
samlResponse, _ = url.QueryUnescape(samlResponse)
|
||||
sp, err := buildSp(provider, samlResponse, host)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
assertionInfo, err := sp.RetrieveAssertionInfo(samlResponse)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
return assertionInfo.NameID, err
|
||||
|
||||
userInfoMap := make(map[string]string)
|
||||
for spAttr, idpAttr := range provider.UserMapping {
|
||||
for _, attr := range assertionInfo.Values {
|
||||
if attr.Name == idpAttr {
|
||||
userInfoMap[spAttr] = attr.Values[0].Value
|
||||
}
|
||||
}
|
||||
}
|
||||
userInfoMap["id"] = assertionInfo.NameID
|
||||
|
||||
customUserInfo := &idp.CustomUserInfo{}
|
||||
err = mapstructure.Decode(userInfoMap, customUserInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userInfo := &idp.UserInfo{
|
||||
Id: customUserInfo.Id,
|
||||
Username: customUserInfo.Username,
|
||||
DisplayName: customUserInfo.DisplayName,
|
||||
Email: customUserInfo.Email,
|
||||
AvatarUrl: customUserInfo.AvatarUrl,
|
||||
}
|
||||
return userInfo, err
|
||||
}
|
||||
|
||||
func GenerateSamlRequest(id, relayState, host, lang string) (auth string, method string, err error) {
|
||||
@@ -146,14 +172,24 @@ func getCertificateFromSamlResponse(samlResponse string, providerType string) (s
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
deStr := strings.Replace(string(de), "\n", "", -1)
|
||||
tagMap := map[string]string{
|
||||
"Aliyun IDaaS": "ds",
|
||||
"Keycloak": "dsig",
|
||||
}
|
||||
var (
|
||||
expression string
|
||||
deStr = strings.Replace(string(de), "\n", "", -1)
|
||||
tagMap = map[string]string{
|
||||
"Aliyun IDaaS": "ds",
|
||||
"Keycloak": "dsig",
|
||||
}
|
||||
)
|
||||
tag := tagMap[providerType]
|
||||
expression := fmt.Sprintf("<%s:X509Certificate>([\\s\\S]*?)</%s:X509Certificate>", tag, tag)
|
||||
if tag == "" {
|
||||
// <ds:X509Certificate>...</ds:X509Certificate>
|
||||
// <dsig:X509Certificate>...</dsig:X509Certificate>
|
||||
// <X509Certificate>...</X509Certificate>
|
||||
// ...
|
||||
expression = "<[^>]*:?X509Certificate>([\\s\\S]*?)<[^>]*:?X509Certificate>"
|
||||
} else {
|
||||
expression = fmt.Sprintf("<%s:X509Certificate>([\\s\\S]*?)</%s:X509Certificate>", tag, tag)
|
||||
}
|
||||
res := regexp.MustCompile(expression).FindStringSubmatch(deStr)
|
||||
return res[1], nil
|
||||
}
|
||||
|
@@ -59,6 +59,10 @@ func AddUserToOriginalDatabase(user *User) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if syncer.IsReadOnly {
|
||||
return nil
|
||||
}
|
||||
|
||||
updatedOUser := syncer.createOriginalUserFromUser(user)
|
||||
_, err = syncer.addUser(updatedOUser)
|
||||
if err != nil {
|
||||
@@ -78,6 +82,10 @@ func UpdateUserToOriginalDatabase(user *User) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if syncer.IsReadOnly {
|
||||
return nil
|
||||
}
|
||||
|
||||
newUser, err := GetUser(user.GetId())
|
||||
if err != nil {
|
||||
return err
|
||||
|
@@ -66,6 +66,13 @@ func getObject(ctx *context.Context) (string, string) {
|
||||
path := ctx.Request.URL.Path
|
||||
|
||||
if method == http.MethodGet {
|
||||
if ctx.Request.URL.Path == "/api/get-policies" && ctx.Input.Query("id") == "/" {
|
||||
adapterId := ctx.Input.Query("adapterId")
|
||||
if adapterId != "" {
|
||||
return util.GetOwnerAndNameFromIdNoCheck(adapterId)
|
||||
}
|
||||
}
|
||||
|
||||
// query == "?id=built-in/admin"
|
||||
id := ctx.Input.Query("id")
|
||||
if id != "" {
|
||||
@@ -79,8 +86,14 @@ func getObject(ctx *context.Context) (string, string) {
|
||||
|
||||
return "", ""
|
||||
} else {
|
||||
body := ctx.Input.RequestBody
|
||||
if path == "/api/add-policy" || path == "/api/remove-policy" || path == "/api/update-policy" {
|
||||
id := ctx.Input.Query("id")
|
||||
if id != "" {
|
||||
return util.GetOwnerAndNameFromIdNoCheck(id)
|
||||
}
|
||||
}
|
||||
|
||||
body := ctx.Input.RequestBody
|
||||
if len(body) == 0 {
|
||||
return ctx.Request.Form.Get("owner"), ctx.Request.Form.Get("name")
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@ import (
|
||||
|
||||
"github.com/beego/beego/context"
|
||||
"github.com/casdoor/casdoor/conf"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
@@ -46,6 +47,46 @@ func getWebBuildFolder() string {
|
||||
return path
|
||||
}
|
||||
|
||||
func fastAutoSignin(ctx *context.Context) (string, error) {
|
||||
userId := getSessionUser(ctx)
|
||||
if userId == "" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
clientId := ctx.Input.Query("client_id")
|
||||
responseType := ctx.Input.Query("response_type")
|
||||
redirectUri := ctx.Input.Query("redirect_uri")
|
||||
scope := ctx.Input.Query("scope")
|
||||
state := ctx.Input.Query("state")
|
||||
nonce := ""
|
||||
codeChallenge := ""
|
||||
if clientId == "" || responseType != "code" || redirectUri == "" {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
application, err := object.GetApplicationByClientId(clientId)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if application == nil {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
if !application.EnableAutoSignin {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
code, err := object.GetOAuthCode(userId, clientId, responseType, redirectUri, scope, state, nonce, codeChallenge, ctx.Request.Host, getAcceptLanguage(ctx))
|
||||
if err != nil {
|
||||
return "", err
|
||||
} else if code.Message != "" {
|
||||
return "", fmt.Errorf(code.Message)
|
||||
}
|
||||
|
||||
res := fmt.Sprintf("%s?code=%s&state=%s", redirectUri, code.Code, state)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func StaticFilter(ctx *context.Context) {
|
||||
urlPath := ctx.Request.URL.Path
|
||||
|
||||
@@ -63,6 +104,19 @@ func StaticFilter(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
if urlPath == "/login/oauth/authorize" {
|
||||
redirectUrl, err := fastAutoSignin(ctx)
|
||||
if err != nil {
|
||||
responseError(ctx, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if redirectUrl != "" {
|
||||
http.Redirect(ctx.ResponseWriter, ctx.Request, redirectUrl, http.StatusFound)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
webBuildFolder := getWebBuildFolder()
|
||||
path := webBuildFolder
|
||||
if urlPath == "/" {
|
||||
|
@@ -36,7 +36,12 @@ func (db *Database) onDDL(header *replication.EventHeader, nextPos mysql.Positio
|
||||
}
|
||||
|
||||
func (db *Database) OnRow(e *canal.RowsEvent) error {
|
||||
log.Info("serverId: ", e.Header.ServerID)
|
||||
if e.Header != nil {
|
||||
log.Info("serverId: ", e.Header.ServerID)
|
||||
} else {
|
||||
log.Info("serverId: e.Header == nil")
|
||||
}
|
||||
|
||||
if strings.Contains(db.Gtid, db.serverUuid) {
|
||||
return nil
|
||||
}
|
||||
@@ -87,11 +92,13 @@ func (db *Database) OnRow(e *canal.RowsEvent) error {
|
||||
pkColumnValue := getPkColumnValues(oldColumnValue, e.Table.PKColumns)
|
||||
updateSql, args, err := getUpdateSql(e.Table.Schema, e.Table.Name, columnNames, newColumnValue, pkColumnNames, pkColumnValue)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
res, err := db.engine.DB().Exec(updateSql, args...)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
log.Info(updateSql, args, res)
|
||||
@@ -113,11 +120,13 @@ func (db *Database) OnRow(e *canal.RowsEvent) error {
|
||||
pkColumnValue := getPkColumnValues(oldColumnValue, e.Table.PKColumns)
|
||||
deleteSql, args, err := getDeleteSql(e.Table.Schema, e.Table.Name, pkColumnNames, pkColumnValue)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
res, err := db.engine.DB().Exec(deleteSql, args...)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
log.Info(deleteSql, args, res)
|
||||
@@ -141,11 +150,13 @@ func (db *Database) OnRow(e *canal.RowsEvent) error {
|
||||
|
||||
insertSql, args, err := getInsertSql(e.Table.Schema, e.Table.Name, columnNames, newColumnValue)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
res, err := db.engine.DB().Exec(insertSql, args...)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
log.Info(insertSql, args, res)
|
||||
|
14
sync/sync.go
14
sync/sync.go
@@ -20,11 +20,21 @@ func startSyncJob(db1 *Database, db2 *Database) error {
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// start canal1 replication
|
||||
go db1.startCanal(db2)
|
||||
go func(db1 *Database, db2 *Database) {
|
||||
err := db1.startCanal(db2)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}(db1, db2)
|
||||
wg.Add(1)
|
||||
|
||||
// start canal2 replication
|
||||
go db2.startCanal(db1)
|
||||
go func(db1 *Database, db2 *Database) {
|
||||
err := db2.startCanal(db1)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}(db1, db2)
|
||||
wg.Add(1)
|
||||
|
||||
wg.Wait()
|
||||
|
@@ -24,7 +24,10 @@ import (
|
||||
)
|
||||
|
||||
func TestStartSyncJob(t *testing.T) {
|
||||
db1 := newDatabase("127.0.0.1", 3306, "casdoor", "root", "123456")
|
||||
db2 := newDatabase("127.0.0.1", 3306, "casdoor2", "root", "123456")
|
||||
startSyncJob(db1, db2)
|
||||
db1 := newDatabase("localhost", 3306, "casdoor", "root", "123456")
|
||||
db2 := newDatabase("localhost", 3306, "casdoor2", "root", "123456")
|
||||
err := startSyncJob(db1, db2)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
16
sync/util.go
16
sync/util.go
@@ -15,9 +15,7 @@
|
||||
package sync
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/xorm-io/xorm"
|
||||
@@ -74,21 +72,23 @@ func createEngine(dataSourceName string) (*xorm.Engine, error) {
|
||||
}
|
||||
|
||||
func getServerId(engin *xorm.Engine) (uint32, error) {
|
||||
res, err := engin.QueryInterface("SELECT @@server_id")
|
||||
record, err := engin.QueryInterface("SELECT @@server_id")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
serverId, _ := strconv.ParseUint(fmt.Sprintf("%s", res[0]["@@server_id"]), 10, 32)
|
||||
return uint32(serverId), nil
|
||||
|
||||
res := uint32(record[0]["@@server_id"].(int64))
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func getServerUuid(engin *xorm.Engine) (string, error) {
|
||||
res, err := engin.QueryString("show variables like 'server_uuid'")
|
||||
record, err := engin.QueryString("show variables like 'server_uuid'")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
serverUuid := fmt.Sprintf("%s", res[0]["Value"])
|
||||
return serverUuid, err
|
||||
|
||||
res := record[0]["Value"]
|
||||
return res, err
|
||||
}
|
||||
|
||||
func getPkColumnNames(columnNames []string, PKColumns []int) []string {
|
||||
|
@@ -24,7 +24,10 @@ import (
|
||||
)
|
||||
|
||||
func FileExist(path string) bool {
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
_, err := os.Stat(path)
|
||||
if os.IsNotExist(err) {
|
||||
return false
|
||||
} else if err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
@@ -640,13 +640,23 @@ class ApplicationEditPage extends React.Component {
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 19 : 2}>
|
||||
{Setting.getLabel(i18next.t("application:Enable SAML C14N10"), i18next.t("application:Enable SAML C14N10 - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={1} >
|
||||
<Switch checked={this.state.application.enableSamlC14n10} onChange={checked => {
|
||||
this.updateApplicationField("enableSamlC14n10", checked);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:SAML Attribute"), i18next.t("general:SAML Attribute - Tooltip"))} :
|
||||
{Setting.getLabel(i18next.t("general:SAML attributes"), i18next.t("general:SAML attributes - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<SamlAttributeTable
|
||||
title={i18next.t("general:SAML Attribute")}
|
||||
title={i18next.t("general:SAML attributes")}
|
||||
table={this.state.application.samlAttributes}
|
||||
application={this.state.application}
|
||||
onUpdateTable={(value) => {this.updateApplicationField("samlAttributes", value);}}
|
||||
|
@@ -44,7 +44,7 @@ class ApplicationListPage extends BaseListPage {
|
||||
enableCodeSignin: false,
|
||||
enableSamlCompress: false,
|
||||
providers: [
|
||||
{name: "provider_captcha_default", canSignUp: false, canSignIn: false, canUnlink: false, prompted: false, alertType: "None"},
|
||||
{name: "provider_captcha_default", canSignUp: false, canSignIn: false, canUnlink: false, prompted: false, signupGroup: "", rule: ""},
|
||||
],
|
||||
signupItems: [
|
||||
{name: "ID", visible: false, required: true, rule: "Random"},
|
||||
|
@@ -379,10 +379,11 @@ class ProviderEditPage extends React.Component {
|
||||
|
||||
loadSamlConfiguration() {
|
||||
const parser = new DOMParser();
|
||||
const xmlDoc = parser.parseFromString(this.state.provider.metadata, "text/xml");
|
||||
const cert = xmlDoc.getElementsByTagName("ds:X509Certificate")[0].childNodes[0].nodeValue;
|
||||
const endpoint = xmlDoc.getElementsByTagName("md:SingleSignOnService")[0].getAttribute("Location");
|
||||
const issuerUrl = xmlDoc.getElementsByTagName("md:EntityDescriptor")[0].getAttribute("entityID");
|
||||
const rawXml = this.state.provider.metadata.replace("\n", "");
|
||||
const xmlDoc = parser.parseFromString(rawXml, "text/xml");
|
||||
const cert = xmlDoc.querySelector("X509Certificate").childNodes[0].nodeValue.replace(" ", "");
|
||||
const endpoint = xmlDoc.querySelector("SingleSignOnService").getAttribute("Location");
|
||||
const issuerUrl = xmlDoc.querySelector("EntityDescriptor").getAttribute("entityID");
|
||||
this.updateProviderField("idP", cert);
|
||||
this.updateProviderField("endpoint", endpoint);
|
||||
this.updateProviderField("issuerUrl", issuerUrl);
|
||||
@@ -491,7 +492,7 @@ class ProviderEditPage extends React.Component {
|
||||
this.updateProviderField("type", value);
|
||||
if (value === "Local File System") {
|
||||
this.updateProviderField("domain", Setting.getFullServerUrl());
|
||||
} else if (value === "Custom") {
|
||||
} else if (value === "Custom" && this.state.provider.category === "OAuth") {
|
||||
this.updateProviderField("customAuthUrl", "https://door.casdoor.com/login/oauth/authorize");
|
||||
this.updateProviderField("scopes", "openid profile email");
|
||||
this.updateProviderField("customTokenUrl", "https://door.casdoor.com/api/login/oauth/access_token");
|
||||
@@ -553,48 +554,54 @@ class ProviderEditPage extends React.Component {
|
||||
)
|
||||
}
|
||||
{
|
||||
this.state.provider.type !== "Custom" ? null : (
|
||||
this.state.provider.type === "Custom" ? (
|
||||
<React.Fragment>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Auth URL"), i18next.t("provider:Auth URL - Tooltip"))}
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.provider.customAuthUrl} onChange={e => {
|
||||
this.updateProviderField("customAuthUrl", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Token URL"), i18next.t("provider:Token URL - Tooltip"))}
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.provider.customTokenUrl} onChange={e => {
|
||||
this.updateProviderField("customTokenUrl", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Scope"), i18next.t("provider:Scope - Tooltip"))}
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.provider.scopes} onChange={e => {
|
||||
this.updateProviderField("scopes", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:UserInfo URL"), i18next.t("provider:UserInfo URL - Tooltip"))}
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.provider.customUserInfoUrl} onChange={e => {
|
||||
this.updateProviderField("customUserInfoUrl", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
{
|
||||
this.state.provider.category === "OAuth" ? (
|
||||
<Col>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Auth URL"), i18next.t("provider:Auth URL - Tooltip"))}
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.provider.customAuthUrl} onChange={e => {
|
||||
this.updateProviderField("customAuthUrl", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Token URL"), i18next.t("provider:Token URL - Tooltip"))}
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.provider.customTokenUrl} onChange={e => {
|
||||
this.updateProviderField("customTokenUrl", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Scope"), i18next.t("provider:Scope - Tooltip"))}
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.provider.scopes} onChange={e => {
|
||||
this.updateProviderField("scopes", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:UserInfo URL"), i18next.t("provider:UserInfo URL - Tooltip"))}
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.provider.customUserInfoUrl} onChange={e => {
|
||||
this.updateProviderField("customUserInfoUrl", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
) : null
|
||||
}
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:User mapping"), i18next.t("provider:User mapping - Tooltip"))} :
|
||||
@@ -631,7 +638,7 @@ class ProviderEditPage extends React.Component {
|
||||
</Col>
|
||||
</Row>
|
||||
</React.Fragment>
|
||||
)
|
||||
) : null
|
||||
}
|
||||
{
|
||||
(this.state.provider.category === "Captcha" && this.state.provider.type === "Default") ||
|
||||
|
@@ -209,6 +209,10 @@ export const OtherProviderInfo = {
|
||||
logo: `${StaticBaseUrl}/img/social_keycloak.png`,
|
||||
url: "https://www.keycloak.org/",
|
||||
},
|
||||
"Custom": {
|
||||
logo: `${StaticBaseUrl}/img/social_custom.png`,
|
||||
url: "https://door.casdoor.com/",
|
||||
},
|
||||
},
|
||||
Payment: {
|
||||
"Dummy": {
|
||||
@@ -866,10 +870,10 @@ export function getClickable(text) {
|
||||
}
|
||||
|
||||
export function getProviderLogoURL(provider) {
|
||||
if (provider.type === "Custom" && provider.customLogo) {
|
||||
return provider.customLogo;
|
||||
}
|
||||
if (provider.category === "OAuth") {
|
||||
if (provider.type === "Custom" && provider.customLogo) {
|
||||
return provider.customLogo;
|
||||
}
|
||||
return `${StaticBaseUrl}/img/social_${provider.type.toLowerCase()}.png`;
|
||||
} else {
|
||||
const info = OtherProviderInfo[provider.category][provider.type];
|
||||
@@ -1014,6 +1018,7 @@ export function getProviderTypeOptions(category) {
|
||||
return ([
|
||||
{id: "Aliyun IDaaS", name: "Aliyun IDaaS"},
|
||||
{id: "Keycloak", name: "Keycloak"},
|
||||
{id: "Custom", name: "Custom"},
|
||||
]);
|
||||
} else if (category === "Payment") {
|
||||
return ([
|
||||
|
@@ -99,7 +99,9 @@ class LoginPage extends React.Component {
|
||||
this.setState({enableCaptchaModal: CaptchaRule.Never});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (prevProps.account !== this.props.account && this.props.account !== undefined) {
|
||||
if (this.props.account && this.props.account.owner === this.props.application?.organization) {
|
||||
const params = new URLSearchParams(this.props.location.search);
|
||||
const silentSignin = params.get("silentSignin");
|
||||
|
@@ -14,7 +14,7 @@
|
||||
|
||||
import React from "react";
|
||||
import {DeleteOutlined, DownOutlined, UpOutlined} from "@ant-design/icons";
|
||||
import {Button, Col, Row, Select, Switch, Table, Tooltip} from "antd";
|
||||
import {Button, Col, Input, Row, Select, Switch, Table, Tooltip} from "antd";
|
||||
import * as Setting from "../Setting";
|
||||
import i18next from "i18next";
|
||||
import * as Provider from "../auth/Provider";
|
||||
@@ -39,7 +39,7 @@ class ProviderTable extends React.Component {
|
||||
}
|
||||
|
||||
addRow(table) {
|
||||
const row = {name: Setting.getNewRowNameForTable(table, "Please select a provider"), canSignUp: true, canSignIn: true, canUnlink: true, alertType: "None", rule: "None"};
|
||||
const row = {name: Setting.getNewRowNameForTable(table, "Please select a provider"), canSignUp: true, canSignIn: true, canUnlink: true, prompted: false, signupGroup: "", rule: "None"};
|
||||
if (table === undefined) {
|
||||
table = [];
|
||||
}
|
||||
@@ -172,6 +172,23 @@ class ProviderTable extends React.Component {
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("provider:Signup group"),
|
||||
dataIndex: "signupGroup",
|
||||
key: "signupGroup",
|
||||
width: "120px",
|
||||
render: (text, record, index) => {
|
||||
if (!["OAuth", "Web3"].includes(record.provider?.category)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Input value={text} onChange={e => {
|
||||
this.updateField(table, index, "signupGroup", e.target.value);
|
||||
}} />
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("application:Rule"),
|
||||
dataIndex: "rule",
|
||||
|
Reference in New Issue
Block a user