This commit is contained in:
mjeremym2 2024-06-11 14:00:34 +08:00 committed by GitHub
commit 3f3a034056
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 111 additions and 53 deletions

View File

@ -242,43 +242,45 @@ The default configuration is as follows:
Location: `api-server/conf/application.yaml`
| Parameters | Default value | Description |
|-------------------------------------------------------|--------------------------------------|------------------------------------------------------------------------------------------------|
| server.port | 12345 | api service communication port |
| server.servlet.session.timeout | 120m | session timeout |
| server.servlet.context-path | /dolphinscheduler/ | request path |
| spring.servlet.multipart.max-file-size | 1024MB | maximum file size |
| spring.servlet.multipart.max-request-size | 1024MB | maximum request size |
| server.jetty.max-http-post-size | 5000000 | jetty maximum post size |
| spring.banner.charset | UTF-8 | message encoding |
| spring.jackson.time-zone | UTC | time zone |
| spring.jackson.date-format | "yyyy-MM-dd HH:mm:ss" | time format |
| spring.messages.basename | i18n/messages | i18n config |
| security.authentication.type | PASSWORD | authentication type |
| security.authentication.ldap.user.admin | read-only-admin | admin user account when you log-in with LDAP |
| security.authentication.ldap.urls | ldap://ldap.forumsys.com:389/ | LDAP urls |
| security.authentication.ldap.base.dn | dc=example,dc=com | LDAP base dn |
| security.authentication.ldap.username | cn=read-only-admin,dc=example,dc=com | LDAP username |
| security.authentication.ldap.password | password | LDAP password |
| security.authentication.ldap.user.identity-attribute | uid | LDAP user identity attribute |
| security.authentication.ldap.user.email-attribute | mail | LDAP user email attribute |
| security.authentication.ldap.user.not-exist-action | CREATE | action when ldap user is not exist,default value: CREATE. Optional values include(CREATE,DENY) |
| security.authentication.ldap.ssl.enable | false | LDAP ssl switch |
| security.authentication.ldap.ssl.trust-store | ldapkeystore.jks | LDAP jks file absolute path |
| security.authentication.ldap.ssl.trust-store-password | password | LDAP jks password |
| security.authentication.casdoor.user.admin | | admin user account when you log-in with Casdoor |
| casdoor.endpoint | | Casdoor server url |
| casdoor.client-id | | id in Casdoor |
| casdoor.client-secret | | secret in Casdoor |
| casdoor.certificate | | certificate in Casdoor |
| casdoor.organization-name | | organization name in Casdoor |
| casdoor.application-name | | application name in Casdoor |
| casdoor.redirect-url | | doplhinscheduler login url |
| api.traffic.control.global.switch | false | traffic control global switch |
| api.traffic.control.max-global-qps-rate | 300 | global max request number per second |
| api.traffic.control.tenant-switch | false | traffic control tenant switch |
| api.traffic.control.default-tenant-qps-rate | 10 | default tenant max request number per second |
| api.traffic.control.customize-tenant-qps-rate | | customize tenant max request number per second |
| Parameters | Default value | Description |
|-------------------------------------------------------|-------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------|
| server.port | 12345 | api service communication port |
| server.servlet.session.timeout | 120m | session timeout |
| server.servlet.context-path | /dolphinscheduler/ | request path |
| spring.servlet.multipart.max-file-size | 1024MB | maximum file size |
| spring.servlet.multipart.max-request-size | 1024MB | maximum request size |
| server.jetty.max-http-post-size | 5000000 | jetty maximum post size |
| spring.banner.charset | UTF-8 | message encoding |
| spring.jackson.time-zone | UTC | time zone |
| spring.jackson.date-format | "yyyy-MM-dd HH:mm:ss" | time format |
| spring.messages.basename | i18n/messages | i18n config |
| security.authentication.type | PASSWORD | authentication type |
| security.authentication.ldap.user.admin | read-only-admin | admin user account when you log-in with LDAP using the uid attribute of the user |
| security.authentication.ldap.user.admin-filter | (&(ou=scientists)(uniqueMember=uid={0},dc=example,dc=com)) | Alternative to "admin" were admin accounts identified by role with LDAP using the uid attribute of the user |
| | (&(sAMAccountName={0})(memberOf=CN=admin,OU=dolphin,DC=example,DC=com)) | Alternative example were role attributes with in the LDAP account (memberOf LDAP setup) |
| security.authentication.ldap.urls | ldap://ldap.forumsys.com:389/ | LDAP urls |
| security.authentication.ldap.base.dn | dc=example,dc=com | LDAP base dn |
| security.authentication.ldap.username | cn=read-only-admin,dc=example,dc=com | LDAP username |
| security.authentication.ldap.password | password | LDAP password |
| security.authentication.ldap.user.identity-attribute | uid | LDAP user identity attribute |
| security.authentication.ldap.user.email-attribute | mail | LDAP user email attribute |
| security.authentication.ldap.user.not-exist-action | CREATE | action when ldap user is not exist,default value: CREATE. Optional values include(CREATE,DENY) |
| security.authentication.ldap.ssl.enable | false | LDAP ssl switch |
| security.authentication.ldap.ssl.trust-store | ldapkeystore.jks | LDAP jks file absolute path |
| security.authentication.ldap.ssl.trust-store-password | password | LDAP jks password |
| security.authentication.casdoor.user.admin | | admin user account when you log-in with Casdoor |
| casdoor.endpoint | | Casdoor server url |
| casdoor.client-id | | id in Casdoor |
| casdoor.client-secret | | secret in Casdoor |
| casdoor.certificate | | certificate in Casdoor |
| casdoor.organization-name | | organization name in Casdoor |
| casdoor.application-name | | application name in Casdoor |
| casdoor.redirect-url | | doplhinscheduler login url |
| api.traffic.control.global.switch | false | traffic control global switch |
| api.traffic.control.max-global-qps-rate | 300 | global max request number per second |
| api.traffic.control.tenant-switch | false | traffic control tenant switch |
| api.traffic.control.default-tenant-qps-rate | 10 | default tenant max request number per second |
| api.traffic.control.customize-tenant-qps-rate | | customize tenant max request number per second |
### Master Server related configuration

View File

@ -20,6 +20,8 @@ package org.apache.dolphinscheduler.api.security.impl.ldap;
import org.apache.dolphinscheduler.api.security.impl.AbstractAuthenticator;
import org.apache.dolphinscheduler.dao.entity.User;
import java.util.Map;
import lombok.NonNull;
import org.springframework.beans.factory.annotation.Autowired;
@ -32,12 +34,13 @@ public class LdapAuthenticator extends AbstractAuthenticator {
@Override
public User login(@NonNull String userId, String password) {
User user = null;
String ldapEmail = ldapService.ldapLogin(userId, password);
if (ldapEmail != null) {
Map<String, String> ldapAttributes = ldapService.ldapLogin(userId, password);
if (ldapAttributes != null && ldapAttributes.containsKey(LdapService.ATTRIBUTE_EMAIL)) {
// check if user exist
user = userService.getUserByUserName(userId);
if (user == null && ldapService.createIfUserNotExists()) {
user = userService.createUser(ldapService.getUserType(userId), userId, ldapEmail);
String ldapEmail = ldapAttributes.get(LdapService.ATTRIBUTE_EMAIL);
user = userService.createUser(ldapService.getUserType(ldapAttributes), userId, ldapEmail);
}
}
return user;

View File

@ -22,6 +22,8 @@ import org.apache.dolphinscheduler.common.enums.UserType;
import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.naming.Context;
@ -46,6 +48,9 @@ import org.springframework.stereotype.Component;
@Slf4j
public class LdapService {
public static final String ATTRIBUTE_EMAIL = "email";
public static final String ATTRIBUTE_USER_TYPE = "userType";
@Value("${security.authentication.ldap.user.admin:#{null}}")
private String adminUserId;
@ -67,6 +72,9 @@ public class LdapService {
@Value("${security.authentication.ldap.user.email-attribute:#{null}}")
private String ldapEmailAttribute;
@Value("${security.authentication.ldap.user.admin-filter:#{null}}")
private String ldapAdminUserFilter;
@Value("${security.authentication.ldap.user.not-exist-action:CREATE}")
private String ldapUserNotExistAction;
@ -81,11 +89,18 @@ public class LdapService {
/***
* get user type by configured admin userId
* @param userId login userId
* @param ldapAttributes login userI ldap attributes (i.e. userId, email, etc...)
* @return user type
*/
public UserType getUserType(String userId) {
return adminUserId.equalsIgnoreCase(userId) ? UserType.ADMIN_USER : UserType.GENERAL_USER;
public UserType getUserType(Map<String, String> ldapAttributes) {
if (ldapAttributes.containsKey(ATTRIBUTE_USER_TYPE)) {
String userType = ldapAttributes.get(ATTRIBUTE_USER_TYPE);
return UserType.valueOf(userType);
}
return UserType.GENERAL_USER;
}
/**
@ -95,9 +110,11 @@ public class LdapService {
* @param userPwd user login password
* @return user email
*/
public String ldapLogin(String userId, String userPwd) {
public Map<String, String> ldapLogin(String userId, String userPwd) {
Map<String, String> ldapAttributeMap = new HashMap<>();
Properties searchEnv = getManagerLdapEnv();
LdapContext ctx = null;
try {
// Connect to the LDAP server and Authenticate with a service user of whom we know the DN and credentials
ctx = new InitialLdapContext(searchEnv, null);
@ -106,10 +123,13 @@ public class LdapService {
sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
EqualsFilter filter = new EqualsFilter(ldapUserIdentifyingAttribute, userId);
NamingEnumeration<SearchResult> results = ctx.search(ldapBaseDn, filter.toString(), sc);
// Get all requested attributes
if (results.hasMore()) {
// get the users DN (distinguishedName) from the result
SearchResult result = results.next();
NamingEnumeration<? extends Attribute> attrs = result.getAttributes().getAll();
while (attrs.hasMore()) {
// Open another connection to the LDAP server with the found DN and the password
searchEnv.put(Context.SECURITY_PRINCIPAL, result.getNameInNamespace());
@ -120,12 +140,30 @@ public class LdapService {
log.warn("invalid ldap credentials or ldap search error", e);
return null;
}
Attribute attr = attrs.next();
if (attr.getID().equals(ldapEmailAttribute)) {
return (String) attr.get();
String value = (String) attr.get();
ldapAttributeMap.put(ATTRIBUTE_EMAIL, value);
}
}
}
// Check for admin role
UserType userType =
userId.equalsIgnoreCase(adminUserId) ? UserType.ADMIN_USER : UserType.GENERAL_USER;
ldapAttributeMap.put(ATTRIBUTE_USER_TYPE, userType.toString());
if (ldapAdminUserFilter != null) {
results = ctx.search(ldapBaseDn, ldapAdminUserFilter, new Object[]{userId}, sc);
if (results.hasMore()) {
// found the users with or part of the admin context
ldapAttributeMap.put(ATTRIBUTE_USER_TYPE, UserType.ADMIN_USER.toString());
}
}
} catch (NamingException e) {
log.error("ldap search error", e);
return null;
@ -139,7 +177,7 @@ public class LdapService {
}
}
return null;
return ldapAttributeMap;
}
/***

View File

@ -109,7 +109,8 @@ public class LdapAuthenticatorTest extends AbstractControllerTest {
@Test
public void testAuthenticate() {
when(ldapService.ldapLogin(ldapUid, ldapUserPwd)).thenReturn(ldapEmail);
Map<String, String> ldapAttributes = Map.of(LdapService.ATTRIBUTE_EMAIL, ldapEmail);
when(ldapService.ldapLogin(ldapUid, ldapUserPwd)).thenReturn(ldapAttributes);
when(sessionService.createSessionIfAbsent(Mockito.any(User.class))).thenReturn(mockSession);
// test username pwd correct and user not exist, config user not exist action deny, so login denied

View File

@ -22,6 +22,7 @@ import org.apache.dolphinscheduler.common.enums.ProfileType;
import org.apache.dolphinscheduler.common.enums.UserType;
import java.lang.reflect.Field;
import java.util.Map;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
@ -49,6 +50,7 @@ import org.springframework.test.context.TestPropertySource;
"security.authentication.ldap.ssl.enable=false",
"security.authentication.ldap.ssl.trust-store=",
"security.authentication.ldap.ssl.trust-store-password=",
"security.authentication.ldap.user.admin-filter=(&(ou=scientists)(uniqueMember=uid={0},dc=example,dc=com))"
})
public class LdapServiceTest {
@ -68,28 +70,37 @@ public class LdapServiceTest {
@Test
public void getUserType() {
UserType userType = ldapService.getUserType("read-only-admin");
UserType userType =
ldapService.getUserType(Map.of(LdapService.ATTRIBUTE_USER_TYPE, UserType.ADMIN_USER.toString()));
Assertions.assertEquals(UserType.ADMIN_USER, userType);
userType = ldapService.getUserType(Map.of());
Assertions.assertEquals(UserType.GENERAL_USER, userType);
}
@Test
public void ldapLogin() throws NoSuchFieldException, IllegalAccessException {
changeSslEnable(false);
String email = ldapService.ldapLogin(username, correctPassword);
Map<String, String> ldapAttributes = ldapService.ldapLogin(username, correctPassword);
String email = ldapAttributes.get(LdapService.ATTRIBUTE_EMAIL);
Assertions.assertEquals("tesla@ldap.forumsys.com", email);
String userType = ldapAttributes.get(LdapService.ATTRIBUTE_USER_TYPE);
Assertions.assertEquals(UserType.ADMIN_USER.toString(), userType);
}
@Test
public void ldapLoginError() throws NoSuchFieldException, IllegalAccessException {
changeSslEnable(false);
String email2 = ldapService.ldapLogin(username, "error password");
Assertions.assertNull(email2);
Map<String, String> ldapAttributes = ldapService.ldapLogin(username, "error password");
Assertions.assertNull(ldapAttributes);
}
@Test
public void ldapLoginSSL() throws NoSuchFieldException, IllegalAccessException {
changeSslEnable(true);
String email = ldapService.ldapLogin(username, correctPassword);
Map<String, String> ldapAttributes = ldapService.ldapLogin(username, correctPassword);
String email = ldapAttributes.get(LdapService.ATTRIBUTE_EMAIL);
Assertions.assertNull(email);
}

View File

@ -105,8 +105,11 @@ security:
username: cn=read-only-admin,dc=example,dc=com
password: password
user:
# admin userId when you use LDAP login
# admin userId when you use LDAP login. Properties admin are admin-filter are not mutually exclusive
# one uses can be identified by userId and the rest using a role based filter
admin: read-only-admin
# filter admin users by groups. eg, all scientists are admin users
# admin-filter: (&(ou=scientists)(uniqueMember=uid={0},dc=example,dc=com))
identity-attribute: uid
email-attribute: mail
# action when ldap user is not exist (supported types: CREATE,DENY)