mirror of
https://github.com/casdoor/casdoor.git
synced 2025-05-23 02:35:49 +08:00
feat: fix LDAP server handle filter without CN field as * (#1705)
* fix: set ldap server default filter name as * * fix: default use built-in organization to bind * chore: use cache reduce the ci test time
This commit is contained in:
parent
0781a3835d
commit
e1842f6b80
91
.github/workflows/build.yml
vendored
91
.github/workflows/build.yml
vendored
@ -9,18 +9,19 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
services:
|
services:
|
||||||
mysql:
|
mysql:
|
||||||
image: mysql:5.7
|
image: mysql:5.7
|
||||||
env:
|
env:
|
||||||
MYSQL_DATABASE: casdoor
|
MYSQL_DATABASE: casdoor
|
||||||
MYSQL_ROOT_PASSWORD: 123456
|
MYSQL_ROOT_PASSWORD: 123456
|
||||||
ports:
|
ports:
|
||||||
- 3306:3306
|
- 3306:3306
|
||||||
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-go@v2
|
- uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: '^1.16.5'
|
go-version: '^1.16.5'
|
||||||
|
cache-dependency-path: ./go.mod
|
||||||
- name: Tests
|
- name: Tests
|
||||||
run: |
|
run: |
|
||||||
go test -v $(go list ./...) -tags skipCi
|
go test -v $(go list ./...) -tags skipCi
|
||||||
@ -31,14 +32,12 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [ go-tests ]
|
needs: [ go-tests ]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-node@v2
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16
|
||||||
# cache
|
cache: 'yarn'
|
||||||
- uses: c-hive/gha-yarn-cache@v2
|
cache-dependency-path: ./web/yarn.lock
|
||||||
with:
|
|
||||||
directory: ./web
|
|
||||||
- run: yarn install && CI=false yarn run build
|
- run: yarn install && CI=false yarn run build
|
||||||
working-directory: ./web
|
working-directory: ./web
|
||||||
|
|
||||||
@ -47,10 +46,11 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: [ go-tests ]
|
needs: [ go-tests ]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-go@v2
|
- uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: '^1.16.5'
|
go-version: '^1.16.5'
|
||||||
|
cache-dependency-path: ./go.mod
|
||||||
- run: go version
|
- run: go version
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
@ -63,13 +63,14 @@ jobs:
|
|||||||
needs: [ go-tests ]
|
needs: [ go-tests ]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-go@v3
|
- uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: '^1.16.5'
|
go-version: '^1.16.5'
|
||||||
|
cache-dependency-path: ./go.mod
|
||||||
|
|
||||||
# gen a dummy config file
|
# gen a dummy config file
|
||||||
- run: touch dummy.yml
|
- run: touch dummy.yml
|
||||||
|
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v3
|
uses: golangci/golangci-lint-action@v3
|
||||||
with:
|
with:
|
||||||
@ -82,35 +83,35 @@ jobs:
|
|||||||
needs: [ go-tests ]
|
needs: [ go-tests ]
|
||||||
services:
|
services:
|
||||||
mysql:
|
mysql:
|
||||||
image: mysql:5.7
|
image: mysql:5.7
|
||||||
env:
|
env:
|
||||||
MYSQL_DATABASE: casdoor
|
MYSQL_DATABASE: casdoor
|
||||||
MYSQL_ROOT_PASSWORD: 123456
|
MYSQL_ROOT_PASSWORD: 123456
|
||||||
ports:
|
ports:
|
||||||
- 3306:3306
|
- 3306:3306
|
||||||
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-go@v2
|
- uses: actions/setup-go@v4
|
||||||
with:
|
with:
|
||||||
go-version: '^1.16.5'
|
go-version: '^1.16.5'
|
||||||
- uses: actions/setup-node@v2
|
cache-dependency-path: ./go.mod
|
||||||
with:
|
- name: start backend
|
||||||
node-version: 16
|
|
||||||
- name: back start
|
|
||||||
run: nohup go run ./main.go &
|
run: nohup go run ./main.go &
|
||||||
working-directory: ./
|
working-directory: ./
|
||||||
- name: front install
|
- uses: actions/setup-node@v3
|
||||||
run: yarn install
|
|
||||||
working-directory: ./web
|
|
||||||
- name: front start
|
|
||||||
run: nohup yarn start &
|
|
||||||
working-directory: ./web
|
|
||||||
- uses: cypress-io/github-action@v4
|
|
||||||
with:
|
with:
|
||||||
working-directory: ./web
|
node-version: 16
|
||||||
|
cache: 'yarn'
|
||||||
|
cache-dependency-path: ./web/yarn.lock
|
||||||
|
- run: yarn install
|
||||||
|
working-directory: ./web
|
||||||
|
- uses: cypress-io/github-action@v5
|
||||||
|
with:
|
||||||
|
start: yarn start
|
||||||
wait-on: 'http://localhost:7001'
|
wait-on: 'http://localhost:7001'
|
||||||
wait-on-timeout: 180
|
wait-on-timeout: 180
|
||||||
|
working-directory: ./web
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v3
|
||||||
if: failure()
|
if: failure()
|
||||||
@ -121,7 +122,7 @@ jobs:
|
|||||||
if: always()
|
if: always()
|
||||||
with:
|
with:
|
||||||
name: cypress-videos
|
name: cypress-videos
|
||||||
path: ./web/cypress/videos
|
path: ./web/cypress/videos
|
||||||
|
|
||||||
release-and-push:
|
release-and-push:
|
||||||
name: Release And Push
|
name: Release And Push
|
||||||
@ -130,11 +131,11 @@ jobs:
|
|||||||
needs: [ frontend, backend, linter, e2e ]
|
needs: [ frontend, backend, linter, e2e ]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: -1
|
fetch-depth: -1
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 16
|
node-version: 16
|
||||||
|
|
||||||
@ -166,10 +167,10 @@ jobs:
|
|||||||
elif [ ${old_array[1]} != ${new_array[1]} ]
|
elif [ ${old_array[1]} != ${new_array[1]} ]
|
||||||
then
|
then
|
||||||
echo ::set-output name=push::'true'
|
echo ::set-output name=push::'true'
|
||||||
|
|
||||||
else
|
else
|
||||||
echo ::set-output name=push::'false'
|
echo ::set-output name=push::'false'
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
|
@ -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.
|
||||||
|
|
||||||
package controllers
|
package ldap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -20,76 +20,78 @@ import (
|
|||||||
|
|
||||||
"github.com/casdoor/casdoor/conf"
|
"github.com/casdoor/casdoor/conf"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/forestmgy/ldapserver"
|
ldap "github.com/forestmgy/ldapserver"
|
||||||
"github.com/lor00x/goldap/message"
|
"github.com/lor00x/goldap/message"
|
||||||
)
|
)
|
||||||
|
|
||||||
func StartLdapServer() {
|
func StartLdapServer() {
|
||||||
server := ldapserver.NewServer()
|
server := ldap.NewServer()
|
||||||
routes := ldapserver.NewRouteMux()
|
routes := ldap.NewRouteMux()
|
||||||
|
|
||||||
routes.Bind(handleBind)
|
routes.Bind(handleBind)
|
||||||
routes.Search(handleSearch).Label(" SEARCH****")
|
routes.Search(handleSearch).Label(" SEARCH****")
|
||||||
|
|
||||||
server.Handle(routes)
|
server.Handle(routes)
|
||||||
server.ListenAndServe("0.0.0.0:" + conf.GetConfigString("ldapServerPort"))
|
err := server.ListenAndServe("0.0.0.0:" + conf.GetConfigString("ldapServerPort"))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleBind(w ldapserver.ResponseWriter, m *ldapserver.Message) {
|
func handleBind(w ldap.ResponseWriter, m *ldap.Message) {
|
||||||
r := m.GetBindRequest()
|
r := m.GetBindRequest()
|
||||||
res := ldapserver.NewBindResponse(ldapserver.LDAPResultSuccess)
|
res := ldap.NewBindResponse(ldap.LDAPResultSuccess)
|
||||||
|
|
||||||
if r.AuthenticationChoice() == "simple" {
|
if r.AuthenticationChoice() == "simple" {
|
||||||
bindusername, bindorg, err := object.GetNameAndOrgFromDN(string(r.Name()))
|
bindUsername, bindOrg, err := getNameAndOrgFromDN(string(r.Name()))
|
||||||
if err != "" {
|
if err != "" {
|
||||||
log.Printf("Bind failed ,ErrMsg=%s", err)
|
log.Printf("Bind failed ,ErrMsg=%s", err)
|
||||||
res.SetResultCode(ldapserver.LDAPResultInvalidDNSyntax)
|
res.SetResultCode(ldap.LDAPResultInvalidDNSyntax)
|
||||||
res.SetDiagnosticMessage("bind failed ErrMsg: " + err)
|
res.SetDiagnosticMessage("bind failed ErrMsg: " + err)
|
||||||
w.Write(res)
|
w.Write(res)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
bindpassword := string(r.AuthenticationSimple())
|
|
||||||
binduser, err := object.CheckUserPassword(bindorg, bindusername, bindpassword, "en")
|
bindPassword := string(r.AuthenticationSimple())
|
||||||
|
bindUser, err := object.CheckUserPassword(object.CasdoorOrganization, bindUsername, bindPassword, "en")
|
||||||
if err != "" {
|
if err != "" {
|
||||||
log.Printf("Bind failed User=%s, Pass=%#v, ErrMsg=%s", string(r.Name()), r.Authentication(), err)
|
log.Printf("Bind failed User=%s, Pass=%#v, ErrMsg=%s", string(r.Name()), r.Authentication(), err)
|
||||||
res.SetResultCode(ldapserver.LDAPResultInvalidCredentials)
|
res.SetResultCode(ldap.LDAPResultInvalidCredentials)
|
||||||
res.SetDiagnosticMessage("invalid credentials ErrMsg: " + err)
|
res.SetDiagnosticMessage("invalid credentials ErrMsg: " + err)
|
||||||
w.Write(res)
|
w.Write(res)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if bindorg == "built-in" {
|
|
||||||
|
if bindOrg == "built-in" || bindUser.IsGlobalAdmin {
|
||||||
m.Client.IsGlobalAdmin, m.Client.IsOrgAdmin = true, true
|
m.Client.IsGlobalAdmin, m.Client.IsOrgAdmin = true, true
|
||||||
} else if binduser.IsAdmin {
|
} else if bindUser.IsAdmin {
|
||||||
m.Client.IsOrgAdmin = true
|
m.Client.IsOrgAdmin = true
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Client.IsAuthenticated = true
|
m.Client.IsAuthenticated = true
|
||||||
m.Client.UserName = bindusername
|
m.Client.UserName = bindUsername
|
||||||
m.Client.OrgName = bindorg
|
m.Client.OrgName = bindOrg
|
||||||
} else {
|
} else {
|
||||||
res.SetResultCode(ldapserver.LDAPResultAuthMethodNotSupported)
|
res.SetResultCode(ldap.LDAPResultAuthMethodNotSupported)
|
||||||
res.SetDiagnosticMessage("Authentication method not supported,Please use Simple Authentication")
|
res.SetDiagnosticMessage("Authentication method not supported,Please use Simple Authentication")
|
||||||
}
|
}
|
||||||
w.Write(res)
|
w.Write(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleSearch(w ldapserver.ResponseWriter, m *ldapserver.Message) {
|
func handleSearch(w ldap.ResponseWriter, m *ldap.Message) {
|
||||||
res := ldapserver.NewSearchResultDoneResponse(ldapserver.LDAPResultSuccess)
|
res := ldap.NewSearchResultDoneResponse(ldap.LDAPResultSuccess)
|
||||||
if !m.Client.IsAuthenticated {
|
if !m.Client.IsAuthenticated {
|
||||||
res.SetResultCode(ldapserver.LDAPResultUnwillingToPerform)
|
res.SetResultCode(ldap.LDAPResultUnwillingToPerform)
|
||||||
w.Write(res)
|
w.Write(res)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
r := m.GetSearchRequest()
|
r := m.GetSearchRequest()
|
||||||
if r.FilterString() == "(objectClass=*)" {
|
if r.FilterString() == "(objectClass=*)" {
|
||||||
w.Write(res)
|
w.Write(res)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
name, org, errCode := object.GetUserNameAndOrgFromBaseDnAndFilter(string(r.BaseObject()), r.FilterString())
|
|
||||||
if errCode != ldapserver.LDAPResultSuccess {
|
|
||||||
res.SetResultCode(errCode)
|
|
||||||
w.Write(res)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Handle Stop Signal (server stop / client disconnected / Abandoned request....)
|
// Handle Stop Signal (server stop / client disconnected / Abandoned request....)
|
||||||
select {
|
select {
|
||||||
case <-m.Done:
|
case <-m.Done:
|
||||||
@ -97,16 +99,17 @@ func handleSearch(w ldapserver.ResponseWriter, m *ldapserver.Message) {
|
|||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
users, errCode := object.GetFilteredUsers(m, name, org)
|
|
||||||
if errCode != ldapserver.LDAPResultSuccess {
|
users, code := GetFilteredUsers(m)
|
||||||
res.SetResultCode(errCode)
|
if code != ldap.LDAPResultSuccess {
|
||||||
|
res.SetResultCode(code)
|
||||||
w.Write(res)
|
w.Write(res)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for i := 0; i < len(users); i++ {
|
|
||||||
user := users[i]
|
for _, user := range users {
|
||||||
dn := fmt.Sprintf("cn=%s,%s", user.Name, string(r.BaseObject()))
|
dn := fmt.Sprintf("cn=%s,%s", user.Name, string(r.BaseObject()))
|
||||||
e := ldapserver.NewSearchResultEntry(dn)
|
e := ldap.NewSearchResultEntry(dn)
|
||||||
e.AddAttribute("cn", message.AttributeValue(user.Name))
|
e.AddAttribute("cn", message.AttributeValue(user.Name))
|
||||||
e.AddAttribute("uid", message.AttributeValue(user.Name))
|
e.AddAttribute("uid", message.AttributeValue(user.Name))
|
||||||
e.AddAttribute("email", message.AttributeValue(user.Email))
|
e.AddAttribute("email", message.AttributeValue(user.Email))
|
||||||
@ -117,22 +120,3 @@ func handleSearch(w ldapserver.ResponseWriter, m *ldapserver.Message) {
|
|||||||
}
|
}
|
||||||
w.Write(res)
|
w.Write(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
// get user password with hash type prefix
|
|
||||||
// TODO not handle salt yet
|
|
||||||
// @return {md5}5f4dcc3b5aa765d61d8327deb882cf99
|
|
||||||
func getUserPasswordWithType(user *object.User) string {
|
|
||||||
org := object.GetOrganizationByUser(user)
|
|
||||||
if org.PasswordType == "" || org.PasswordType == "plain" {
|
|
||||||
return user.Password
|
|
||||||
}
|
|
||||||
prefix := org.PasswordType
|
|
||||||
if prefix == "salt" {
|
|
||||||
prefix = "sha256"
|
|
||||||
} else if prefix == "md5-salt" {
|
|
||||||
prefix = "md5"
|
|
||||||
} else if prefix == "pbkdf2-salt" {
|
|
||||||
prefix = "pbkdf2"
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("{%s}%s", prefix, user.Password)
|
|
||||||
}
|
|
116
ldap/util.go
Normal file
116
ldap/util.go
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/object"
|
||||||
|
"github.com/casdoor/casdoor/util"
|
||||||
|
|
||||||
|
ldap "github.com/forestmgy/ldapserver"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getNameAndOrgFromDN(DN string) (string, string, string) {
|
||||||
|
DNFields := strings.Split(DN, ",")
|
||||||
|
params := make(map[string]string, len(DNFields))
|
||||||
|
for _, field := range DNFields {
|
||||||
|
if strings.Contains(field, "=") {
|
||||||
|
k := strings.Split(field, "=")
|
||||||
|
params[k[0]] = k[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if params["cn"] == "" {
|
||||||
|
return "", "", "please use Admin Name format like cn=xxx,ou=xxx,dc=example,dc=com"
|
||||||
|
}
|
||||||
|
if params["ou"] == "" {
|
||||||
|
return params["cn"], object.CasdoorOrganization, ""
|
||||||
|
}
|
||||||
|
return params["cn"], params["ou"], ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNameAndOrgFromFilter(baseDN, filter string) (string, string, int) {
|
||||||
|
if !strings.Contains(baseDN, "ou=") {
|
||||||
|
return "", "", ldap.LDAPResultInvalidDNSyntax
|
||||||
|
}
|
||||||
|
|
||||||
|
name, org, _ := getNameAndOrgFromDN(fmt.Sprintf("cn=%s,", getUsername(filter)) + baseDN)
|
||||||
|
return name, org, ldap.LDAPResultSuccess
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUsername(filter string) string {
|
||||||
|
nameIndex := strings.Index(filter, "cn=")
|
||||||
|
if nameIndex == -1 {
|
||||||
|
return "*"
|
||||||
|
}
|
||||||
|
|
||||||
|
var name string
|
||||||
|
for i := nameIndex + 3; filter[i] != ')'; i++ {
|
||||||
|
name = name + string(filter[i])
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetFilteredUsers(m *ldap.Message) (filteredUsers []*object.User, code int) {
|
||||||
|
r := m.GetSearchRequest()
|
||||||
|
name, org, code := getNameAndOrgFromFilter(string(r.BaseObject()), r.FilterString())
|
||||||
|
if code != ldap.LDAPResultSuccess {
|
||||||
|
return nil, code
|
||||||
|
}
|
||||||
|
|
||||||
|
if name == "*" && m.Client.IsOrgAdmin { // get all users from organization 'org'
|
||||||
|
if m.Client.IsGlobalAdmin && org == "*" {
|
||||||
|
filteredUsers = object.GetGlobalUsers()
|
||||||
|
return filteredUsers, ldap.LDAPResultSuccess
|
||||||
|
}
|
||||||
|
if m.Client.IsGlobalAdmin || org == m.Client.OrgName {
|
||||||
|
filteredUsers = object.GetUsers(org)
|
||||||
|
return filteredUsers, ldap.LDAPResultSuccess
|
||||||
|
} else {
|
||||||
|
return nil, ldap.LDAPResultInsufficientAccessRights
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hasPermission, err := object.CheckUserPermission(fmt.Sprintf("%s/%s", m.Client.OrgName, m.Client.UserName), fmt.Sprintf("%s/%s", org, name), org, true, "en")
|
||||||
|
if !hasPermission {
|
||||||
|
log.Printf("ErrMsg = %v", err.Error())
|
||||||
|
return nil, ldap.LDAPResultInsufficientAccessRights
|
||||||
|
}
|
||||||
|
user := object.GetUser(util.GetId(org, name))
|
||||||
|
filteredUsers = append(filteredUsers, user)
|
||||||
|
return filteredUsers, ldap.LDAPResultSuccess
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get user password with hash type prefix
|
||||||
|
// TODO not handle salt yet
|
||||||
|
// @return {md5}5f4dcc3b5aa765d61d8327deb882cf99
|
||||||
|
func getUserPasswordWithType(user *object.User) string {
|
||||||
|
org := object.GetOrganizationByUser(user)
|
||||||
|
if org.PasswordType == "" || org.PasswordType == "plain" {
|
||||||
|
return user.Password
|
||||||
|
}
|
||||||
|
prefix := org.PasswordType
|
||||||
|
if prefix == "salt" {
|
||||||
|
prefix = "sha256"
|
||||||
|
} else if prefix == "md5-salt" {
|
||||||
|
prefix = "md5"
|
||||||
|
} else if prefix == "pbkdf2-salt" {
|
||||||
|
prefix = "pbkdf2"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("{%s}%s", prefix, user.Password)
|
||||||
|
}
|
4
main.go
4
main.go
@ -23,7 +23,7 @@ import (
|
|||||||
_ "github.com/beego/beego/session/redis"
|
_ "github.com/beego/beego/session/redis"
|
||||||
"github.com/casdoor/casdoor/authz"
|
"github.com/casdoor/casdoor/authz"
|
||||||
"github.com/casdoor/casdoor/conf"
|
"github.com/casdoor/casdoor/conf"
|
||||||
"github.com/casdoor/casdoor/controllers"
|
"github.com/casdoor/casdoor/ldap"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/proxy"
|
"github.com/casdoor/casdoor/proxy"
|
||||||
"github.com/casdoor/casdoor/routers"
|
"github.com/casdoor/casdoor/routers"
|
||||||
@ -81,7 +81,7 @@ func main() {
|
|||||||
// logs.SetLevel(logs.LevelInformational)
|
// logs.SetLevel(logs.LevelInformational)
|
||||||
logs.SetLogFuncCall(false)
|
logs.SetLogFuncCall(false)
|
||||||
|
|
||||||
go controllers.StartLdapServer()
|
go ldap.StartLdapServer()
|
||||||
|
|
||||||
beego.Run(fmt.Sprintf(":%v", port))
|
beego.Run(fmt.Sprintf(":%v", port))
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ func LdapUsersToLdapRespUsers(users []ldapUser) []LdapRespUser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func isMicrosoftAD(Conn *goldap.Conn) (bool, error) {
|
func isMicrosoftAD(Conn *goldap.Conn) (bool, error) {
|
||||||
SearchFilter := "(objectclass=*)"
|
SearchFilter := "(objectClass=*)"
|
||||||
SearchAttributes := []string{"vendorname", "vendorversion", "isGlobalCatalogReady", "forestFunctionality"}
|
SearchAttributes := []string{"vendorname", "vendorversion", "isGlobalCatalogReady", "forestFunctionality"}
|
||||||
|
|
||||||
searchReq := goldap.NewSearchRequest("",
|
searchReq := goldap.NewSearchRequest("",
|
||||||
@ -126,7 +126,7 @@ func isMicrosoftAD(Conn *goldap.Conn) (bool, error) {
|
|||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
if len(searchResult.Entries) == 0 {
|
if len(searchResult.Entries) == 0 {
|
||||||
return false, errors.New("no result")
|
return false, nil
|
||||||
}
|
}
|
||||||
isMicrosoft := false
|
isMicrosoft := false
|
||||||
var ldapServerType ldapServerType
|
var ldapServerType ldapServerType
|
||||||
|
@ -1,74 +0,0 @@
|
|||||||
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package object
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/forestmgy/ldapserver"
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetNameAndOrgFromDN(DN string) (string, string, string) {
|
|
||||||
DNValue := strings.Split(DN, ",")
|
|
||||||
if len(DNValue) == 1 || strings.ToLower(DNValue[0])[0] != 'c' || strings.ToLower(DNValue[1])[0] != 'o' {
|
|
||||||
return "", "", "please use correct Admin Name format like cn=xxx,ou=xxx,dc=example,dc=com"
|
|
||||||
}
|
|
||||||
return DNValue[0][3:], DNValue[1][3:], ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetUserNameAndOrgFromBaseDnAndFilter(baseDN, filter string) (string, string, int) {
|
|
||||||
if !strings.Contains(baseDN, "ou=") || !strings.Contains(filter, "cn=") {
|
|
||||||
return "", "", ldapserver.LDAPResultInvalidDNSyntax
|
|
||||||
}
|
|
||||||
name := getUserNameFromFilter(filter)
|
|
||||||
_, org, _ := GetNameAndOrgFromDN(fmt.Sprintf("cn=%s,", name) + baseDN)
|
|
||||||
errCode := ldapserver.LDAPResultSuccess
|
|
||||||
return name, org, errCode
|
|
||||||
}
|
|
||||||
|
|
||||||
func getUserNameFromFilter(filter string) string {
|
|
||||||
nameIndex := strings.Index(filter, "cn=")
|
|
||||||
var name string
|
|
||||||
for i := nameIndex + 3; filter[i] != ')'; i++ {
|
|
||||||
name = name + string(filter[i])
|
|
||||||
}
|
|
||||||
return name
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetFilteredUsers(m *ldapserver.Message, name, org string) ([]*User, int) {
|
|
||||||
var filteredUsers []*User
|
|
||||||
if name == "*" && m.Client.IsOrgAdmin { // get all users from organization 'org'
|
|
||||||
if m.Client.OrgName == "built-in" && org == "*" {
|
|
||||||
filteredUsers = GetGlobalUsers()
|
|
||||||
return filteredUsers, ldapserver.LDAPResultSuccess
|
|
||||||
} else if m.Client.OrgName == "built-in" || org == m.Client.OrgName {
|
|
||||||
filteredUsers = GetUsers(org)
|
|
||||||
return filteredUsers, ldapserver.LDAPResultSuccess
|
|
||||||
} else {
|
|
||||||
return nil, ldapserver.LDAPResultInsufficientAccessRights
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
hasPermission, err := CheckUserPermission(fmt.Sprintf("%s/%s", m.Client.OrgName, m.Client.UserName), fmt.Sprintf("%s/%s", org, name), org, true, "en")
|
|
||||||
if !hasPermission {
|
|
||||||
log.Printf("ErrMsg = %v", err.Error())
|
|
||||||
return nil, ldapserver.LDAPResultInsufficientAccessRights
|
|
||||||
}
|
|
||||||
user := getUser(org, name)
|
|
||||||
filteredUsers = append(filteredUsers, user)
|
|
||||||
return filteredUsers, ldapserver.LDAPResultSuccess
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user