diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/auth/AuthEntryPoint.java b/modules/core/src/main/java/com/bytedesk/core/rbac/auth/AuthEntryPoint.java index f67da75ee9..8431b6f080 100644 --- a/modules/core/src/main/java/com/bytedesk/core/rbac/auth/AuthEntryPoint.java +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/auth/AuthEntryPoint.java @@ -2,7 +2,7 @@ * @Author: jackning 270580156@qq.com * @Date: 2024-01-29 12:45:01 * @LastEditors: jackning 270580156@qq.com - * @LastEditTime: 2024-11-12 14:32:01 + * @LastEditTime: 2025-03-10 12:24:39 * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk * Please be aware of the BSL license restrictions before installing Bytedesk IM – * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/auth/ldap/LdapSecurityConfig.java b/modules/core/src/main/java/com/bytedesk/core/rbac/auth/ldap/LdapSecurityConfig.java new file mode 100644 index 0000000000..7e7a3148be --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/auth/ldap/LdapSecurityConfig.java @@ -0,0 +1,72 @@ +/* + * @Author: jackning 270580156@qq.com + * @Date: 2025-03-10 12:25:11 + * @LastEditors: jackning 270580156@qq.com + * @LastEditTime: 2025-03-10 12:38:51 + * @Description: bytedesk.com https://github.com/Bytedesk/bytedesk + * Please be aware of the BSL license restrictions before installing Bytedesk IM – + * selling, reselling, or hosting Bytedesk IM as a service is a breach of the terms and automatically terminates your rights under the license. + * Business Source License 1.1: https://github.com/Bytedesk/bytedesk/blob/main/LICENSE + * contact: 270580156@qq.com + * + * Copyright (c) 2025 by bytedesk.com, All Rights Reserved. + */ +package com.bytedesk.core.rbac.auth.ldap; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.ldap.core.LdapTemplate; +import org.springframework.ldap.core.support.LdapContextSource; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.authentication.configuration.GlobalAuthenticationConfigurerAdapter; +import org.springframework.security.ldap.authentication.BindAuthenticator; +import org.springframework.security.ldap.authentication.LdapAuthenticationProvider; +import org.springframework.security.ldap.search.FilterBasedLdapUserSearch; +import org.springframework.security.ldap.userdetails.LdapUserDetailsMapper; + +@Configuration +public class LdapSecurityConfig extends GlobalAuthenticationConfigurerAdapter { + + @Override + public void init(AuthenticationManagerBuilder auth) throws Exception { + auth.authenticationProvider(ldapAuthenticationProvider()); + } + + @Bean + public AuthenticationProvider ldapAuthenticationProvider() { + LdapAuthenticationProvider provider = new LdapAuthenticationProvider(bindAuthenticator()); + provider.setUserDetailsContextMapper(new LdapUserDetailsMapper()); + return provider; + } + + @Bean + public BindAuthenticator bindAuthenticator() { + BindAuthenticator authenticator = new BindAuthenticator(contextSource()); + authenticator.setUserSearch(userSearch()); + return authenticator; + } + + @Bean + public FilterBasedLdapUserSearch userSearch() { + return new FilterBasedLdapUserSearch( + "${spring.ldap.base}", // 搜索基础 + "(uid={0})", // 用户搜索过滤器 + contextSource()); + } + + @Bean + public LdapContextSource contextSource() { + LdapContextSource contextSource = new LdapContextSource(); + contextSource.setUrl("${spring.ldap.urls}"); + contextSource.setBase("${spring.ldap.base}"); + contextSource.setUserDn("${spring.ldap.username}"); + contextSource.setPassword("${spring.ldap.password}"); + return contextSource; + } + + @Bean + public LdapTemplate ldapTemplate() { + return new LdapTemplate(contextSource()); + } +} \ No newline at end of file diff --git a/modules/core/src/main/java/com/bytedesk/core/rbac/auth/ldap/LdapUserService.java b/modules/core/src/main/java/com/bytedesk/core/rbac/auth/ldap/LdapUserService.java new file mode 100644 index 0000000000..82fa5e658a --- /dev/null +++ b/modules/core/src/main/java/com/bytedesk/core/rbac/auth/ldap/LdapUserService.java @@ -0,0 +1,19 @@ +package com.bytedesk.core.rbac.auth.ldap; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.ldap.core.LdapTemplate; +import org.springframework.ldap.filter.EqualsFilter; +import org.springframework.ldap.filter.Filter; +import org.springframework.stereotype.Service; + +@Service +public class LdapUserService { + + @Autowired + private LdapTemplate ldapTemplate; + + public boolean authenticate(String username, String password) { + Filter filter = new EqualsFilter("uid", username); + return ldapTemplate.authenticate("", filter.encode(), password); + } +} \ No newline at end of file diff --git a/modules/pom.xml b/modules/pom.xml index 7e3862ffd5..12e4c52f36 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -135,6 +135,24 @@ provided + + + org.springframework.security + spring-security-ldap + + + + org.springframework.boot + spring-boot-starter-data-ldap + provided + + + + com.unboundid + unboundid-ldapsdk + test + + @@ -411,6 +429,7 @@ provided + diff --git a/starter/compose.yaml b/starter/compose.yaml deleted file mode 100644 index 916fc2b794..0000000000 --- a/starter/compose.yaml +++ /dev/null @@ -1,82 +0,0 @@ -services: - bytedesk-mysql: - image: mysql:latest - container_name: mysql-bytedesk - environment: - MYSQL_DATABASE: bytedesk - MYSQL_ROOT_PASSWORD: r8FqfdbWUaN3 - ports: - - "3306:3306" - volumes: - - mysql_data:/var/lib/mysql - networks: - - bytedesk-network - - bytedesk-redis: - image: redis/redis-stack-server:latest - container_name: redis-bytedesk - ports: - - "6379:6379" - environment: - - REDIS_ARGS=--requirepass qfRxz3tVT8Nh - volumes: - - redis_data:/data - networks: - - bytedesk-network - - bytedesk-ollama: - image: ollama/ollama:latest - container_name: ollama-bytedesk - ports: - - "11434:11434" - volumes: - - ollama_data:/root/.ollama - environment: - - OLLAMA_MODELS=deepseek-r1:1.5b - command: serve - networks: - - bytedesk-network - - bytedesk-prometheus: - image: prom/prometheus:latest - container_name: prometheus-bytedesk - ports: - - "9090:9090" - command: - - '--config.file=/etc/prometheus/prometheus.yml' - - '--storage.tsdb.path=/prometheus' - - '--web.enable-lifecycle' - - '--web.console.libraries=/usr/share/prometheus/console_libraries' - - '--web.console.templates=/usr/share/prometheus/consoles' - - '--storage.tsdb.retention.time=15d' - - '--web.enable-admin-api' - - '--web.external-url=http://localhost:9090' - volumes: - - prometheus_data:/prometheus - - ./prometheus.yml:/etc/prometheus/prometheus.yml - networks: - - bytedesk-network - - bytedesk-grafana: - image: grafana/grafana:latest - container_name: grafana-bytedesk - ports: - - "3000:3000" - environment: - - GF_SECURITY_ADMIN_USER=admin - - GF_SECURITY_ADMIN_PASSWORD=admin - volumes: - - grafana_data:/var/lib/grafana - networks: - - bytedesk-network - -volumes: - mysql_data: - redis_data: - ollama_data: - prometheus_data: - grafana_data: - -networks: - bytedesk-network: - driver: bridge diff --git a/starter/src/main/resources/application-dev.properties b/starter/src/main/resources/application-dev.properties index d98cf3bca2..715170d103 100644 --- a/starter/src/main/resources/application-dev.properties +++ b/starter/src/main/resources/application-dev.properties @@ -143,6 +143,22 @@ bytedesk.redis.pool-config.maxIdle=64 bytedesk.redis.pool-config.maxTotal=64 bytedesk.redis.pool-config.minIdle=8 +# =============================== +# LDAP Configuration +# =============================== +# LDAP 服务器地址 +spring.ldap.urls=ldap://127.0.0.1:389 +# LDAP 基础目录 +spring.ldap.base=dc=example,dc=com +# LDAP 管理员用户名 +spring.ldap.username=cn=admin,dc=example,dc=com +# LDAP 管理员密码 +spring.ldap.password=admin +# LDAP 是否只读 +spring.ldap.anonymous-read-only=false +# LDAP 是否启用匿名访问 +spring.ldap.anonymous-enabled=true + # =============================== #=logging # https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#appendix.application-properties.core diff --git a/starter/src/test/java/com/bytedesk/auth/ldap/LdapAuthenticationTest.java b/starter/src/test/java/com/bytedesk/auth/ldap/LdapAuthenticationTest.java new file mode 100644 index 0000000000..ef767933b6 --- /dev/null +++ b/starter/src/test/java/com/bytedesk/auth/ldap/LdapAuthenticationTest.java @@ -0,0 +1,33 @@ +package com.bytedesk.auth.ldap; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; + +import com.bytedesk.core.rbac.auth.ldap.LdapUserService; + +@SpringBootTest +@ActiveProfiles("test") +public class LdapAuthenticationTest { + + @Autowired + private LdapUserService ldapUserService; + + @Test + public void testAuthentication() { + // 测试正确的用户名和密码 + assertTrue(ldapUserService.authenticate("admin", "admin123")); + assertTrue(ldapUserService.authenticate("test", "test123")); + + // 测试错误的密码 + assertFalse(ldapUserService.authenticate("admin", "wrongpassword")); + assertFalse(ldapUserService.authenticate("test", "wrongpassword")); + + // 测试不存在的用户 + assertFalse(ldapUserService.authenticate("nonexistent", "password")); + } +} \ No newline at end of file diff --git a/starter/src/test/resources/application-test.properties b/starter/src/test/resources/application-test.properties new file mode 100644 index 0000000000..9ca7d44856 --- /dev/null +++ b/starter/src/test/resources/application-test.properties @@ -0,0 +1,11 @@ +# 嵌入式LDAP服务器配置 +spring.ldap.embedded.base-dn=dc=bytedesk,dc=com +spring.ldap.embedded.port=8389 +spring.ldap.embedded.ldif=classpath:test-server.ldif +spring.ldap.embedded.validation.enabled=false + +# LDAP客户端配置 +spring.ldap.urls=ldap://localhost:8389 +spring.ldap.base=dc=bytedesk,dc=com +spring.ldap.username=uid=admin,ou=people,dc=bytedesk,dc=com +spring.ldap.password=admin123 \ No newline at end of file diff --git a/starter/src/test/resources/test-server.ldif b/starter/src/test/resources/test-server.ldif new file mode 100644 index 0000000000..89669e8804 --- /dev/null +++ b/starter/src/test/resources/test-server.ldif @@ -0,0 +1,30 @@ +dn: dc=bytedesk,dc=com +objectclass: top +objectclass: domain +objectclass: extensibleObject +dc: bytedesk + +dn: ou=people,dc=bytedesk,dc=com +objectclass: top +objectclass: organizationalUnit +ou: people + +dn: uid=admin,ou=people,dc=bytedesk,dc=com +objectclass: top +objectclass: person +objectclass: organizationalPerson +objectclass: inetOrgPerson +cn: Admin +sn: Admin +uid: admin +userPassword: admin123 + +dn: uid=test,ou=people,dc=bytedesk,dc=com +objectclass: top +objectclass: person +objectclass: organizationalPerson +objectclass: inetOrgPerson +cn: Test User +sn: User +uid: test +userPassword: test123 \ No newline at end of file