Skip to content

Commit

Permalink
[LDAP] Add LDAP Authentication Provider Support. (#269)
Browse files Browse the repository at this point in the history
Co-authored-by: BilwaST <stbilwa@gmail.com>
  • Loading branch information
shashwatsai and BilwaST authored Jan 17, 2025
1 parent 68ffa3f commit 90d05b0
Show file tree
Hide file tree
Showing 28 changed files with 561 additions and 33 deletions.
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,3 +238,29 @@ NOTE: This feature is currently useful when execution is done through the API. T
Execute the following SQL to upgrade the database:

```ALTER TABLE `t_st_job_instance` ADD COLUMN `error_message` varchar(4096) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL;```

#### 2. Upgrade from 1.0.2 or before to 1.0.3 or after.
- Execute the following SQL to upgrade the database:
```
ALTER TABLE `user` ADD COLUMN `auth_provider` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT 'DB';
```
- Enabling LDAP Support,
- For LDAP support, you need to add the LDAP server configurations and include LDAP in the list of authentication providers in the application.yml file.
- If no authentication providers are defined, default DB strategy will be used, and no changes are required.
- Below is a sample configuration for both the authentication providers and LDAP server settings.
```
# sample application.yaml
spring:
ldap:
url: ldap://localhost:389
search:
base: ou=people,dc=example,dc=com
filter: (uid={0})
domain: example.com
seatunnel:
authentication:
providers:
- DB
- LDAP
```
25 changes: 24 additions & 1 deletion README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -231,4 +231,27 @@ sh bin/seatunnel-backend-daemon.sh start

```ALTER TABLE `t_st_job_instance` ADD COLUMN `error_message` varchar(4096) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL;```


#### 2. 从1.0.2或更早版本升级到1.0.3或更高版本。
- 执行以下SQL语句以升级数据库:
```
ALTER TABLE `user` ADD COLUMN `auth_provider` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL DEFAULT 'DB';
```
- 启用LDAP支持,
- 要启用LDAP支持,您需要在`application.yml`文件中添加LDAP服务器配置,并将LDAP包含在认证提供者列表中。
- 如果未定义任何认证提供者,将使用默认的DB策略,不需要做任何更改。
- 以下是认证提供者和LDAP服务器设置的示例配置。
```
# sample application.yaml
spring:
ldap:
url: ldap://localhost:389
search:
base: ou=people,dc=example,dc=com
filter: (uid={0})
domain: example.com
seatunnel:
authentication:
providers:
- DB
- LDAP
```
11 changes: 11 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@

<spring-boot.version>2.6.8</spring-boot.version>
<spring.version>5.3.20</spring.version>
<spring.security.version>5.6.5</spring.security.version>
<mybatis-plus-boot-starter.version>3.5.3.1</mybatis-plus-boot-starter.version>
<druid-spring-boot-starter.version>1.2.9</druid-spring-boot-starter.version>
<springfox-swagger.version>2.6.1</springfox-swagger.version>
Expand Down Expand Up @@ -349,6 +350,16 @@
<artifactId>spring-boot-starter-jdbc</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
Expand Down
9 changes: 9 additions & 0 deletions seatunnel-server/seatunnel-app/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,15 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
</dependency>

<dependency>
<groupId>com.baomidou</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -655,4 +655,7 @@ private Constants() {
public static final int DEFAULT_ALERT_GROUP_ID = 1;

public static final String TASK_ID = "taskId";

public static final String AUTHENTICATION_PROVIDER_LDAP = "LDAP";
public static final String AUTHENTICATION_PROVIDER_DB = "DB";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.seatunnel.app.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.ldap.core.support.LdapContextSource;
import org.springframework.ldap.core.support.SimpleDirContextAuthenticationStrategy;
import org.springframework.security.core.Authentication;
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
import org.springframework.security.ldap.authentication.BindAuthenticator;
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
import org.springframework.security.ldap.search.FilterBasedLdapUserSearch;
import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class LdapAuthenticationBuilder {

@Value("${spring.ldap.url}")
private String ldapUrl;

@Value("${spring.ldap.search.base}")
private String ldapSearchBase;

@Value("${spring.ldap.search.domain}")
private String ldapSearchDomain;

public LdapAuthenticationProvider buildLdapAuthenticationProvider(
Authentication authentication) {

LdapContextSource ldapContextSource = new DefaultSpringSecurityContextSource(ldapUrl);
String ldapBindUser = authentication.getName();
ldapContextSource.setUserDn(
new StringBuilder()
.append(ldapBindUser)
.append("@")
.append(ldapSearchDomain)
.toString());
ldapContextSource.setPassword(authentication.getCredentials().toString());
ldapContextSource.setCacheEnvironmentProperties(false);
ldapContextSource.setAuthenticationStrategy(new SimpleDirContextAuthenticationStrategy());
ldapContextSource.afterPropertiesSet();

String ldapAuthID =
ldapBindUser.toLowerCase().endsWith("@" + ldapSearchDomain)
? ldapBindUser
: ldapBindUser + "@" + ldapSearchDomain;
String searchFilter = "(userPrincipalName=" + ldapAuthID + ")";
FilterBasedLdapUserSearch userSearch =
new FilterBasedLdapUserSearch(ldapSearchBase, searchFilter, ldapContextSource);
userSearch.setSearchSubtree(true);
BindAuthenticator authenticator = new BindAuthenticator(ldapContextSource);
authenticator.setUserSearch(userSearch);
LdapAuthenticationProvider ldapAuthenticationProvider =
new LdapAuthenticationProvider(authenticator);
return ldapAuthenticationProvider;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.seatunnel.app.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

import lombok.Data;

import java.util.ArrayList;
import java.util.List;

@Data
@Configuration
@ConfigurationProperties(prefix = "spring.authentication")
public class SeatunnelAuthenticationProvidersConfig {
private List<String> providers = new ArrayList<>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.seatunnel.app.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;

import lombok.extern.slf4j.Slf4j;

@Configuration
@Slf4j
public class SeatunnelLdapAuthenticationProvider implements AuthenticationProvider {

@Autowired LdapAuthenticationBuilder ldapAuthenticationBuilder;

@Override
public boolean supports(Class<?> authentication) {
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}

@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
try {
LdapAuthenticationProvider ldapAuthenticationProvider =
ldapAuthenticationBuilder.buildLdapAuthenticationProvider(authentication);
return ldapAuthenticationProvider.authenticate(authentication);
} catch (BadCredentialsException ex) {
log.error("Invalid credentials for user : {}", authentication.getName());
throw new BadCredentialsException("Invalid credentials");
} catch (Exception ex) {
log.error(
"Error while authenticating user : {}, reason :{}",
authentication.getName(),
ex.getMessage());
throw new AuthenticationException(ex.getMessage().toString()) {
@Override
public String getMessage() {
return super.getMessage();
}
};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
Expand Down Expand Up @@ -110,8 +111,10 @@ public Result<Void> disable(
}

@PostMapping("/login")
public Result<UserSimpleInfoRes> login(@RequestBody UserLoginReq req) {
return Result.success(iUserService.login(req));
public Result<UserSimpleInfoRes> login(
@RequestBody UserLoginReq req,
@RequestHeader(value = "X-Seatunnel-Auth-Type", required = false) String authType) {
return Result.success(iUserService.login(req, authType));
}

@PatchMapping("/logout")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public interface IUserDao {

User getByName(String user);

User checkPassword(String username, String password);
User checkPassword(String username, String password, String authProvider);

long insertLoginLog(UserLoginLogDto dto);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public int add(UpdateUserDto dto) {
user.setPassword(dto.getPassword());
user.setType((byte) dto.getType());
user.setStatus((byte) dto.getStatus());
user.setAuthProvider(dto.getAuthProvider());

userMapper.insert(user);
return user.getId();
Expand Down Expand Up @@ -114,8 +115,8 @@ public User getByName(String user) {
}

@Override
public User checkPassword(String username, String password) {
return userMapper.selectByNameAndPasswd(username, password);
public User checkPassword(String username, String password, String authProvider) {
return userMapper.selectByNameAndPasswd(username, password, authProvider);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,6 @@ public class User {
private Date createTime;

private Date updateTime;

private String authProvider;
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ List<User> selectBySelectiveAndPage(
int countBySelective(@Param("user") User user);

User selectByNameAndPasswd(
@Param("username") String username, @Param("password") String password);
@Param("username") String username,
@Param("password") String password,
@Param("authProvider") String authProvider);

List<User> queryEnabledUsers();
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ public class UpdateUserDto {
private String password;
private int status;
private int type;
private String authProvider;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.seatunnel.app.security.authentication.strategy;

import org.apache.seatunnel.app.dal.entity.User;
import org.apache.seatunnel.app.domain.request.user.UserLoginReq;

public interface IAuthenticationStrategy {
User authenticate(UserLoginReq req);
}
Loading

0 comments on commit 90d05b0

Please sign in to comment.