mirror of
https://github.com/iflytek/skillhub.git
synced 2026-10-04 02:34:22 +00:00
Signed-off-by: jangrui <admin@jangrui.com>
This commit is contained in:
parent
098616dcb6
commit
0b4714f735
6 changed files with 483 additions and 2 deletions
|
|
@ -104,6 +104,14 @@ skillhub:
|
|||
code-expiry: ${SKILLHUB_AUTH_PASSWORD_RESET_CODE_EXPIRY:PT10M}
|
||||
email-from-address: ${SKILLHUB_AUTH_PASSWORD_RESET_FROM_ADDRESS:noreply@skillhub.local}
|
||||
email-from-name: ${SKILLHUB_AUTH_PASSWORD_RESET_FROM_NAME:SkillHub}
|
||||
ldap:
|
||||
enabled: ${SKILLHUB_LDAP_ENABLED:false}
|
||||
url: ${SKILLHUB_LDAP_URL:}
|
||||
base: ${SKILLHUB_LDAP_BASE:}
|
||||
username: ${SKILLHUB_LDAP_USERNAME:}
|
||||
password: ${SKILLHUB_LDAP_PASSWORD:}
|
||||
user-search-attribute: ${SKILLHUB_LDAP_USER_SEARCH_ATTRIBUTE:uid}
|
||||
user-search-base: ${SKILLHUB_LDAP_USER_SEARCH_BASE:}
|
||||
public:
|
||||
base-url: ${SKILLHUB_PUBLIC_BASE_URL:}
|
||||
access-policy:
|
||||
|
|
@ -213,6 +221,9 @@ management:
|
|||
endpoint:
|
||||
health:
|
||||
show-details: when-authorized
|
||||
health:
|
||||
ldap:
|
||||
enabled: false
|
||||
metrics:
|
||||
tags:
|
||||
application: skillhub
|
||||
|
|
|
|||
|
|
@ -44,6 +44,14 @@
|
|||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-ldap</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ldap</groupId>
|
||||
<artifactId>spring-ldap-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,103 @@
|
|||
package com.iflytek.skillhub.auth.config;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Configuration properties for LDAP authentication.
|
||||
*/
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "skillhub.ldap")
|
||||
public class LdapProperties {
|
||||
|
||||
/**
|
||||
* Whether LDAP authentication is enabled.
|
||||
*/
|
||||
private boolean enabled = false;
|
||||
|
||||
/**
|
||||
* LDAP server URL (e.g., ldap://localhost:389).
|
||||
*/
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* Base DN for LDAP searches (e.g., dc=example,dc=com).
|
||||
*/
|
||||
private String base;
|
||||
|
||||
/**
|
||||
* DN of the user to bind for LDAP searches.
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* Password for the LDAP bind user.
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* LDAP attribute to use for username lookup (e.g., uid, sAMAccountName).
|
||||
*/
|
||||
private String userSearchAttribute = "uid";
|
||||
|
||||
/**
|
||||
* Search base for user lookup (relative to base).
|
||||
*/
|
||||
private String userSearchBase = "";
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getBase() {
|
||||
return base;
|
||||
}
|
||||
|
||||
public void setBase(String base) {
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getUserSearchAttribute() {
|
||||
return userSearchAttribute;
|
||||
}
|
||||
|
||||
public void setUserSearchAttribute(String userSearchAttribute) {
|
||||
this.userSearchAttribute = userSearchAttribute;
|
||||
}
|
||||
|
||||
public String getUserSearchBase() {
|
||||
return userSearchBase;
|
||||
}
|
||||
|
||||
public void setUserSearchBase(String userSearchBase) {
|
||||
this.userSearchBase = userSearchBase;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,314 @@
|
|||
package com.iflytek.skillhub.auth.ldap;
|
||||
|
||||
import com.iflytek.skillhub.auth.config.LdapProperties;
|
||||
import com.iflytek.skillhub.auth.exception.AuthFlowException;
|
||||
import com.iflytek.skillhub.auth.rbac.PlatformPrincipal;
|
||||
import com.iflytek.skillhub.auth.rbac.PlatformRoleDefaults;
|
||||
import com.iflytek.skillhub.auth.repository.UserRoleBindingRepository;
|
||||
import com.iflytek.skillhub.domain.namespace.GlobalNamespaceMembershipService;
|
||||
import com.iflytek.skillhub.domain.user.UserAccount;
|
||||
import com.iflytek.skillhub.domain.user.UserAccountRepository;
|
||||
import com.iflytek.skillhub.domain.user.UserStatus;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.naming.Context;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.Attribute;
|
||||
import javax.naming.directory.Attributes;
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.directory.InitialDirContext;
|
||||
import javax.naming.directory.SearchControls;
|
||||
import javax.naming.directory.SearchResult;
|
||||
import javax.naming.ldap.LdapName;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.ldap.core.LdapTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Handles LDAP authentication for enterprise directory integration.
|
||||
*/
|
||||
@Service
|
||||
public class LdapAuthService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(LdapAuthService.class);
|
||||
|
||||
private final LdapProperties ldapProperties;
|
||||
private final LdapTemplate ldapTemplate;
|
||||
private final UserAccountRepository userAccountRepository;
|
||||
private final UserRoleBindingRepository userRoleBindingRepository;
|
||||
private final GlobalNamespaceMembershipService globalNamespaceMembershipService;
|
||||
|
||||
public LdapAuthService(LdapProperties ldapProperties,
|
||||
LdapTemplate ldapTemplate,
|
||||
UserAccountRepository userAccountRepository,
|
||||
UserRoleBindingRepository userRoleBindingRepository,
|
||||
GlobalNamespaceMembershipService globalNamespaceMembershipService) {
|
||||
this.ldapProperties = ldapProperties;
|
||||
this.ldapTemplate = ldapTemplate;
|
||||
this.userAccountRepository = userAccountRepository;
|
||||
this.userRoleBindingRepository = userRoleBindingRepository;
|
||||
this.globalNamespaceMembershipService = globalNamespaceMembershipService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticates a user against the LDAP server.
|
||||
* If the user doesn't exist in the local database, creates a new user based on LDAP attributes.
|
||||
*
|
||||
* @param username the username
|
||||
* @param password the password
|
||||
* @return PlatformPrincipal if authentication succeeds
|
||||
* @throws AuthFlowException if authentication fails
|
||||
*/
|
||||
@Transactional
|
||||
public PlatformPrincipal login(String username, String password) {
|
||||
log.info("Starting LDAP authentication for username: {}", username);
|
||||
|
||||
if (!ldapProperties.isEnabled()) {
|
||||
log.warn("LDAP authentication is not enabled");
|
||||
throw new AuthFlowException(HttpStatus.SERVICE_UNAVAILABLE, "error.auth.ldap.disabled");
|
||||
}
|
||||
|
||||
log.debug("LDAP URL: {}, Base: {}, SearchBase: {}, SearchAttr: {}",
|
||||
ldapProperties.getUrl(),
|
||||
ldapProperties.getBase(),
|
||||
ldapProperties.getUserSearchBase(),
|
||||
ldapProperties.getUserSearchAttribute());
|
||||
|
||||
// First, try to find the user in LDAP and authenticate
|
||||
String userDn = findUserDn(username);
|
||||
log.debug("LDAP findUserDn result for {}: {}", username, userDn);
|
||||
|
||||
if (userDn == null) {
|
||||
log.warn("User {} not found in LDAP directory", username);
|
||||
throw new AuthFlowException(HttpStatus.UNAUTHORIZED, "error.auth.ldap.userNotFound");
|
||||
}
|
||||
|
||||
// Authenticate against LDAP
|
||||
log.debug("Attempting LDAP bind for user DN: {}", userDn);
|
||||
boolean authenticated = authenticateLdap(userDn, password);
|
||||
log.debug("LDAP bind result for {}: {}", username, authenticated);
|
||||
|
||||
if (!authenticated) {
|
||||
log.warn("LDAP authentication failed for username: {}", username);
|
||||
throw new AuthFlowException(HttpStatus.UNAUTHORIZED, "error.auth.ldap.invalidCredentials");
|
||||
}
|
||||
|
||||
// Get user attributes from LDAP
|
||||
log.debug("Fetching user attributes from LDAP for DN: {}", userDn);
|
||||
Attributes userAttributes = getUserAttributes(userDn);
|
||||
if (userAttributes == null) {
|
||||
log.error("Failed to fetch user attributes from LDAP for DN: {}", userDn);
|
||||
throw new AuthFlowException(HttpStatus.INTERNAL_SERVER_ERROR, "error.auth.ldap.fetchUserFailed");
|
||||
}
|
||||
|
||||
// Find or create local user account
|
||||
log.debug("Finding or creating local user account for username: {}", username);
|
||||
UserAccount user = findOrCreateLdapUser(username, userAttributes);
|
||||
|
||||
// Check if user can login (status check)
|
||||
log.debug("Checking user status for user: {}, status: {}", username, user.getStatus());
|
||||
ensureUserCanLogin(user);
|
||||
|
||||
log.info("LDAP authentication successful for username: {}", username);
|
||||
return buildPrincipal(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the user account status allows login.
|
||||
*/
|
||||
private void ensureUserCanLogin(UserAccount user) {
|
||||
if (user.getStatus() == UserStatus.DISABLED) {
|
||||
throw new AuthFlowException(HttpStatus.FORBIDDEN, "error.auth.local.accountDisabled");
|
||||
}
|
||||
if (user.getStatus() == UserStatus.PENDING) {
|
||||
throw new AuthFlowException(HttpStatus.FORBIDDEN, "error.auth.local.accountPending");
|
||||
}
|
||||
if (user.getStatus() == UserStatus.MERGED) {
|
||||
throw new AuthFlowException(HttpStatus.FORBIDDEN, "error.auth.local.accountMerged");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the DN (Distinguished Name) of a user in LDAP.
|
||||
*/
|
||||
private String findUserDn(String username) {
|
||||
DirContext ctx = null;
|
||||
try {
|
||||
ctx = createLdapContext();
|
||||
String searchFilter = "(" + ldapProperties.getUserSearchAttribute() + "={0})";
|
||||
String searchBase = ldapProperties.getUserSearchBase().isEmpty()
|
||||
? ldapProperties.getBase()
|
||||
: ldapProperties.getUserSearchBase() + "," + ldapProperties.getBase();
|
||||
|
||||
SearchControls searchControls = new SearchControls();
|
||||
searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
|
||||
searchControls.setReturningAttributes(new String[0]);
|
||||
|
||||
javax.naming.NamingEnumeration<SearchResult> results = ctx.search(searchBase, searchFilter, new Object[]{username}, searchControls);
|
||||
|
||||
if (results.hasMore()) {
|
||||
SearchResult result = results.next();
|
||||
return result.getNameInNamespace();
|
||||
}
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
} finally {
|
||||
closeContext(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an LDAP context for searching.
|
||||
*/
|
||||
private DirContext createLdapContext() throws NamingException {
|
||||
Hashtable<String, String> env = new Hashtable<>();
|
||||
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
|
||||
env.put(Context.PROVIDER_URL, ldapProperties.getUrl());
|
||||
env.put(Context.SECURITY_AUTHENTICATION, "simple");
|
||||
|
||||
if (ldapProperties.getUsername() != null && !ldapProperties.getUsername().isEmpty()) {
|
||||
env.put(Context.SECURITY_PRINCIPAL, ldapProperties.getUsername());
|
||||
env.put(Context.SECURITY_CREDENTIALS, ldapProperties.getPassword());
|
||||
}
|
||||
|
||||
return new InitialDirContext(env);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes an LDAP context.
|
||||
*/
|
||||
private void closeContext(DirContext ctx) {
|
||||
if (ctx != null) {
|
||||
try {
|
||||
ctx.close();
|
||||
} catch (NamingException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticates a user against the LDAP server using their DN and password.
|
||||
*/
|
||||
private boolean authenticateLdap(String userDn, String password) {
|
||||
try {
|
||||
Hashtable<String, String> env = new Hashtable<>();
|
||||
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
|
||||
env.put(Context.PROVIDER_URL, ldapProperties.getUrl());
|
||||
env.put(Context.SECURITY_AUTHENTICATION, "simple");
|
||||
env.put(Context.SECURITY_PRINCIPAL, userDn);
|
||||
env.put(Context.SECURITY_CREDENTIALS, password);
|
||||
|
||||
DirContext ctx = new InitialDirContext(env);
|
||||
ctx.close();
|
||||
return true;
|
||||
} catch (NamingException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves user attributes from LDAP.
|
||||
*/
|
||||
private Attributes getUserAttributes(String userDn) {
|
||||
try {
|
||||
Hashtable<String, String> env = new Hashtable<>();
|
||||
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
|
||||
env.put(Context.PROVIDER_URL, ldapProperties.getUrl());
|
||||
env.put(Context.SECURITY_AUTHENTICATION, "simple");
|
||||
|
||||
// Use bind DN if configured, otherwise anonymous bind
|
||||
if (ldapProperties.getUsername() != null && !ldapProperties.getUsername().isEmpty()) {
|
||||
env.put(Context.SECURITY_PRINCIPAL, ldapProperties.getUsername());
|
||||
env.put(Context.SECURITY_CREDENTIALS, ldapProperties.getPassword());
|
||||
}
|
||||
|
||||
DirContext ctx = new InitialDirContext(env);
|
||||
Attributes attrs = ctx.getAttributes(new LdapName(userDn));
|
||||
ctx.close();
|
||||
return attrs;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an existing LDAP user or creates a new one based on LDAP attributes.
|
||||
* Note: This method only finds users by email, as the repository doesn't support displayName lookup.
|
||||
*/
|
||||
private UserAccount findOrCreateLdapUser(String username, Attributes attributes) {
|
||||
String email = getAttributeValue(attributes, "mail");
|
||||
String displayName = getAttributeValue(attributes, "displayName");
|
||||
|
||||
if (displayName == null || displayName.isEmpty()) {
|
||||
displayName = getAttributeValue(attributes, "cn");
|
||||
}
|
||||
if (displayName == null || displayName.isEmpty()) {
|
||||
displayName = username;
|
||||
}
|
||||
|
||||
UserAccount user = null;
|
||||
|
||||
// Try to find by email first
|
||||
if (email != null && !email.isEmpty()) {
|
||||
user = userAccountRepository.findByEmailIgnoreCase(email.toLowerCase()).orElse(null);
|
||||
}
|
||||
|
||||
// If not found, create a new user
|
||||
if (user == null) {
|
||||
String normalizedEmail = email != null ? email.toLowerCase() : null;
|
||||
|
||||
user = new UserAccount(
|
||||
"usr_" + UUID.randomUUID(),
|
||||
displayName,
|
||||
normalizedEmail,
|
||||
null
|
||||
);
|
||||
user.setStatus(UserStatus.ACTIVE);
|
||||
userAccountRepository.save(user);
|
||||
globalNamespaceMembershipService.ensureMember(user.getId());
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string attribute value from LDAP attributes.
|
||||
*/
|
||||
private String getAttributeValue(Attributes attributes, String attrName) {
|
||||
try {
|
||||
Attribute attr = attributes.get(attrName);
|
||||
if (attr != null && attr.get() != null) {
|
||||
return attr.get().toString();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Ignore and return null
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a PlatformPrincipal from a UserAccount.
|
||||
*/
|
||||
private PlatformPrincipal buildPrincipal(UserAccount user) {
|
||||
Set<String> roles = userRoleBindingRepository.findByUserId(user.getId()).stream()
|
||||
.map(binding -> binding.getRole().getCode())
|
||||
.collect(Collectors.toSet());
|
||||
roles = PlatformRoleDefaults.withDefaultUserRole(roles);
|
||||
return new PlatformPrincipal(
|
||||
user.getId(),
|
||||
user.getDisplayName(),
|
||||
user.getEmail(),
|
||||
user.getAvatarUrl(),
|
||||
"ldap",
|
||||
roles
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
package com.iflytek.skillhub.auth.local;
|
||||
|
||||
import com.iflytek.skillhub.auth.config.LdapProperties;
|
||||
import com.iflytek.skillhub.auth.exception.AuthFlowException;
|
||||
import com.iflytek.skillhub.auth.ldap.LdapAuthService;
|
||||
import com.iflytek.skillhub.auth.rbac.PlatformPrincipal;
|
||||
import com.iflytek.skillhub.auth.rbac.PlatformRoleDefaults;
|
||||
import com.iflytek.skillhub.auth.repository.UserRoleBindingRepository;
|
||||
|
|
@ -16,6 +18,8 @@ import java.util.Set;
|
|||
import java.util.UUID;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
|
@ -28,6 +32,8 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
@Service
|
||||
public class LocalAuthService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(LocalAuthService.class);
|
||||
|
||||
private static final Pattern USERNAME_PATTERN = Pattern.compile("^[A-Za-z0-9_]{3,64}$");
|
||||
private static final Pattern EMAIL_PATTERN = Pattern.compile("^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$");
|
||||
private static final int MAX_FAILED_ATTEMPTS = 5;
|
||||
|
|
@ -44,6 +50,8 @@ public class LocalAuthService {
|
|||
private final PasswordPolicyValidator passwordPolicyValidator;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
private final Clock clock;
|
||||
private final LdapProperties ldapProperties;
|
||||
private final LdapAuthService ldapAuthService;
|
||||
|
||||
public LocalAuthService(LocalCredentialRepository credentialRepository,
|
||||
UserAccountRepository userAccountRepository,
|
||||
|
|
@ -51,7 +59,9 @@ public class LocalAuthService {
|
|||
GlobalNamespaceMembershipService globalNamespaceMembershipService,
|
||||
PasswordPolicyValidator passwordPolicyValidator,
|
||||
PasswordEncoder passwordEncoder,
|
||||
Clock clock) {
|
||||
Clock clock,
|
||||
LdapProperties ldapProperties,
|
||||
LdapAuthService ldapAuthService) {
|
||||
this.credentialRepository = credentialRepository;
|
||||
this.userAccountRepository = userAccountRepository;
|
||||
this.userRoleBindingRepository = userRoleBindingRepository;
|
||||
|
|
@ -59,6 +69,8 @@ public class LocalAuthService {
|
|||
this.passwordPolicyValidator = passwordPolicyValidator;
|
||||
this.passwordEncoder = passwordEncoder;
|
||||
this.clock = clock;
|
||||
this.ldapProperties = ldapProperties;
|
||||
this.ldapAuthService = ldapAuthService;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -107,6 +119,7 @@ public class LocalAuthService {
|
|||
/**
|
||||
* Authenticates a local account and returns the principal snapshot used to
|
||||
* establish a web session.
|
||||
* If the user is not found locally, falls back to LDAP authentication if enabled.
|
||||
*/
|
||||
@Transactional
|
||||
public PlatformPrincipal login(String username, String password) {
|
||||
|
|
@ -115,7 +128,29 @@ public class LocalAuthService {
|
|||
.orElse(null);
|
||||
|
||||
if (credential == null) {
|
||||
// Blur timing to prevent username enumeration
|
||||
passwordEncoder.matches(password == null ? "" : password, DUMMY_PASSWORD_HASH);
|
||||
|
||||
// Fallback to LDAP authentication if enabled
|
||||
if (ldapProperties.isEnabled()) {
|
||||
log.info("Local user not found, attempting LDAP authentication for username: {}", username);
|
||||
log.debug("LDAP enabled: {}, URL: {}, Base: {}",
|
||||
ldapProperties.isEnabled(),
|
||||
ldapProperties.getUrl(),
|
||||
ldapProperties.getBase());
|
||||
try {
|
||||
PlatformPrincipal ldapPrincipal = ldapAuthService.login(username, password);
|
||||
log.info("LDAP authentication successful for username: {}", username);
|
||||
return ldapPrincipal;
|
||||
} catch (AuthFlowException e) {
|
||||
log.warn("LDAP authentication failed for username: {}, error: {}", username, e.getMessage());
|
||||
// LDAP authentication failed, throw invalid credentials
|
||||
throw invalidCredentials();
|
||||
}
|
||||
} else {
|
||||
log.debug("LDAP authentication is disabled, rejecting login for username: {}", username);
|
||||
}
|
||||
|
||||
throw invalidCredentials();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,9 +9,11 @@ import static org.mockito.Mockito.mock;
|
|||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import com.iflytek.skillhub.auth.config.LdapProperties;
|
||||
import com.iflytek.skillhub.auth.exception.AuthFlowException;
|
||||
import com.iflytek.skillhub.auth.entity.Role;
|
||||
import com.iflytek.skillhub.auth.entity.UserRoleBinding;
|
||||
import com.iflytek.skillhub.auth.ldap.LdapAuthService;
|
||||
import com.iflytek.skillhub.auth.repository.UserRoleBindingRepository;
|
||||
import com.iflytek.skillhub.domain.namespace.GlobalNamespaceMembershipService;
|
||||
import com.iflytek.skillhub.domain.user.UserAccount;
|
||||
|
|
@ -51,6 +53,12 @@ class LocalAuthServiceTest {
|
|||
@Mock
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Mock
|
||||
private LdapProperties ldapProperties;
|
||||
|
||||
@Mock
|
||||
private LdapAuthService ldapAuthService;
|
||||
|
||||
private LocalAuthService service;
|
||||
|
||||
@BeforeEach
|
||||
|
|
@ -62,7 +70,9 @@ class LocalAuthServiceTest {
|
|||
globalNamespaceMembershipService,
|
||||
new PasswordPolicyValidator(),
|
||||
passwordEncoder,
|
||||
CLOCK
|
||||
CLOCK,
|
||||
ldapProperties,
|
||||
ldapAuthService
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue