mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-22 16:43:35 +00:00
chore: support LDAPS
This commit is contained in:
36
.env.example
36
.env.example
@@ -59,3 +59,39 @@ TRUST_PROXY=true
|
||||
|
||||
# 🔒 客户端限制(可选)
|
||||
# ALLOW_CUSTOM_CLIENTS=false
|
||||
|
||||
# 🔐 LDAP 认证配置
|
||||
LDAP_ENABLED=false
|
||||
LDAP_URL=ldaps://ldap-1.test1.bj.yxops.net:636
|
||||
LDAP_BIND_DN=cn=admin,dc=example,dc=com
|
||||
LDAP_BIND_PASSWORD=admin_password
|
||||
LDAP_SEARCH_BASE=dc=example,dc=com
|
||||
LDAP_SEARCH_FILTER=(uid={{username}})
|
||||
LDAP_SEARCH_ATTRIBUTES=dn,uid,cn,mail,givenName,sn
|
||||
LDAP_TIMEOUT=5000
|
||||
LDAP_CONNECT_TIMEOUT=10000
|
||||
|
||||
# 🔒 LDAP TLS/SSL 配置 (用于 ldaps:// URL)
|
||||
# 是否忽略证书验证错误 (设置为false可忽略自签名证书错误)
|
||||
LDAP_TLS_REJECT_UNAUTHORIZED=true
|
||||
# CA 证书文件路径 (可选,用于自定义CA证书)
|
||||
# LDAP_TLS_CA_FILE=/path/to/ca-cert.pem
|
||||
# 客户端证书文件路径 (可选,用于双向认证)
|
||||
# LDAP_TLS_CERT_FILE=/path/to/client-cert.pem
|
||||
# 客户端私钥文件路径 (可选,用于双向认证)
|
||||
# LDAP_TLS_KEY_FILE=/path/to/client-key.pem
|
||||
# 服务器名称 (可选,用于 SNI)
|
||||
# LDAP_TLS_SERVERNAME=ldap.example.com
|
||||
|
||||
# 🗺️ LDAP 用户属性映射
|
||||
LDAP_USER_ATTR_USERNAME=uid
|
||||
LDAP_USER_ATTR_DISPLAY_NAME=cn
|
||||
LDAP_USER_ATTR_EMAIL=mail
|
||||
LDAP_USER_ATTR_FIRST_NAME=givenName
|
||||
LDAP_USER_ATTR_LAST_NAME=sn
|
||||
|
||||
# 👥 用户管理配置
|
||||
USER_MANAGEMENT_ENABLED=false
|
||||
DEFAULT_USER_ROLE=user
|
||||
USER_SESSION_TIMEOUT=86400000
|
||||
MAX_API_KEYS_PER_USER=5
|
||||
@@ -131,7 +131,20 @@ const config = {
|
||||
searchFilter: process.env.LDAP_SEARCH_FILTER || '(uid={{username}})',
|
||||
searchAttributes: process.env.LDAP_SEARCH_ATTRIBUTES ? process.env.LDAP_SEARCH_ATTRIBUTES.split(',') : ['dn', 'uid', 'cn', 'mail', 'givenName', 'sn'],
|
||||
timeout: parseInt(process.env.LDAP_TIMEOUT) || 5000,
|
||||
connectTimeout: parseInt(process.env.LDAP_CONNECT_TIMEOUT) || 10000
|
||||
connectTimeout: parseInt(process.env.LDAP_CONNECT_TIMEOUT) || 10000,
|
||||
// TLS/SSL 配置
|
||||
tls: {
|
||||
// 是否忽略证书错误 (用于自签名证书)
|
||||
rejectUnauthorized: process.env.LDAP_TLS_REJECT_UNAUTHORIZED !== 'false', // 默认验证证书,设置为false则忽略
|
||||
// CA证书文件路径 (可选,用于自定义CA证书)
|
||||
ca: process.env.LDAP_TLS_CA_FILE ? require('fs').readFileSync(process.env.LDAP_TLS_CA_FILE) : undefined,
|
||||
// 客户端证书文件路径 (可选,用于双向认证)
|
||||
cert: process.env.LDAP_TLS_CERT_FILE ? require('fs').readFileSync(process.env.LDAP_TLS_CERT_FILE) : undefined,
|
||||
// 客户端私钥文件路径 (可选,用于双向认证)
|
||||
key: process.env.LDAP_TLS_KEY_FILE ? require('fs').readFileSync(process.env.LDAP_TLS_KEY_FILE) : undefined,
|
||||
// 服务器名称 (用于SNI,可选)
|
||||
servername: process.env.LDAP_TLS_SERVERNAME || undefined
|
||||
}
|
||||
},
|
||||
userMapping: {
|
||||
username: process.env.LDAP_USER_ATTR_USERNAME || 'uid',
|
||||
|
||||
@@ -12,20 +12,76 @@ class LdapService {
|
||||
// 🔗 创建LDAP客户端连接
|
||||
createClient() {
|
||||
try {
|
||||
const client = ldap.createClient({
|
||||
const clientOptions = {
|
||||
url: this.config.server.url,
|
||||
timeout: this.config.server.timeout,
|
||||
connectTimeout: this.config.server.connectTimeout,
|
||||
reconnect: true
|
||||
})
|
||||
}
|
||||
|
||||
// 如果使用 LDAPS (SSL/TLS),添加 TLS 选项
|
||||
if (this.config.server.url.toLowerCase().startsWith('ldaps://')) {
|
||||
const tlsOptions = {}
|
||||
|
||||
// 证书验证设置
|
||||
if (this.config.server.tls) {
|
||||
if (typeof this.config.server.tls.rejectUnauthorized === 'boolean') {
|
||||
tlsOptions.rejectUnauthorized = this.config.server.tls.rejectUnauthorized
|
||||
}
|
||||
|
||||
// CA 证书
|
||||
if (this.config.server.tls.ca) {
|
||||
tlsOptions.ca = this.config.server.tls.ca
|
||||
}
|
||||
|
||||
// 客户端证书和私钥 (双向认证)
|
||||
if (this.config.server.tls.cert) {
|
||||
tlsOptions.cert = this.config.server.tls.cert
|
||||
}
|
||||
|
||||
if (this.config.server.tls.key) {
|
||||
tlsOptions.key = this.config.server.tls.key
|
||||
}
|
||||
|
||||
// 服务器名称 (SNI)
|
||||
if (this.config.server.tls.servername) {
|
||||
tlsOptions.servername = this.config.server.tls.servername
|
||||
}
|
||||
}
|
||||
|
||||
clientOptions.tlsOptions = tlsOptions
|
||||
|
||||
logger.debug('🔒 Creating LDAPS client with TLS options:', {
|
||||
url: this.config.server.url,
|
||||
rejectUnauthorized: tlsOptions.rejectUnauthorized,
|
||||
hasCA: !!tlsOptions.ca,
|
||||
hasCert: !!tlsOptions.cert,
|
||||
hasKey: !!tlsOptions.key,
|
||||
servername: tlsOptions.servername
|
||||
})
|
||||
}
|
||||
|
||||
const client = ldap.createClient(clientOptions)
|
||||
|
||||
// 设置错误处理
|
||||
client.on('error', (err) => {
|
||||
logger.error('🔌 LDAP client error:', err)
|
||||
if (err.code === 'CERT_HAS_EXPIRED' || err.code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE') {
|
||||
logger.error('🔒 LDAP TLS certificate error:', {
|
||||
code: err.code,
|
||||
message: err.message,
|
||||
hint: 'Consider setting LDAP_TLS_REJECT_UNAUTHORIZED=false for self-signed certificates'
|
||||
})
|
||||
} else {
|
||||
logger.error('🔌 LDAP client error:', err)
|
||||
}
|
||||
})
|
||||
|
||||
client.on('connect', () => {
|
||||
logger.info('🔗 LDAP client connected successfully')
|
||||
if (this.config.server.url.toLowerCase().startsWith('ldaps://')) {
|
||||
logger.info('🔒 LDAPS client connected successfully')
|
||||
} else {
|
||||
logger.info('🔗 LDAP client connected successfully')
|
||||
}
|
||||
})
|
||||
|
||||
client.on('connectTimeout', () => {
|
||||
@@ -280,16 +336,30 @@ class LdapService {
|
||||
|
||||
// 📊 获取LDAP配置信息(不包含敏感信息)
|
||||
getConfigInfo() {
|
||||
return {
|
||||
const configInfo = {
|
||||
enabled: this.config.enabled,
|
||||
server: {
|
||||
url: this.config.server.url,
|
||||
searchBase: this.config.server.searchBase,
|
||||
searchFilter: this.config.server.searchFilter,
|
||||
timeout: this.config.server.timeout
|
||||
timeout: this.config.server.timeout,
|
||||
connectTimeout: this.config.server.connectTimeout
|
||||
},
|
||||
userMapping: this.config.userMapping
|
||||
}
|
||||
|
||||
// 添加 TLS 配置信息(不包含敏感数据)
|
||||
if (this.config.server.url.toLowerCase().startsWith('ldaps://') && this.config.server.tls) {
|
||||
configInfo.server.tls = {
|
||||
rejectUnauthorized: this.config.server.tls.rejectUnauthorized,
|
||||
hasCA: !!this.config.server.tls.ca,
|
||||
hasCert: !!this.config.server.tls.cert,
|
||||
hasKey: !!this.config.server.tls.key,
|
||||
servername: this.config.server.tls.servername
|
||||
}
|
||||
}
|
||||
|
||||
return configInfo
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user