1.下载LDAP server 并安装, liferay支持如下的server,推荐使用apacheds,或openLDAP

2.下载一个LDAP客户端工具,官方网站都有提供 ,推荐使用 jxplorer,测试能否正常连接。
3. Enterprise Admin->setting->authentication->LDAP,Enable使用LDAP验证,Required是否必须通过LDAP验证,如果不勾选通过liferay验证即可。

/**
* LDAP验证
* @param companyId
* @param emailAddress
* @param screenName
* @param userId
* @param password
* @return
* @throws Exception
*/
protected int authenticate(
long companyId, String emailAddress, String screenName, long userId,
String password)
throws Exception {
//是否需要LDAP验证
if (!PortalLDAPUtil.isAuthEnabled(companyId)) {
if (_log.isDebugEnabled()) {
_log.debug("Authenticator is not enabled");
}
return SUCCESS;
}
if (_log.isDebugEnabled()) {
_log.debug("Authenticator is enabled");
}
// Make exceptions for omniadmins so that if they break the LDAP
// configuration, they can still login to fix the problem
//如果此用户是管理员的角色就返回成功
if (authenticateOmniadmin(companyId, emailAddress, userId) == SUCCESS) {
return SUCCESS;
}
//相对DN
String baseDN = PrefsPropsUtil.getString(
companyId, PropsUtil.LDAP_BASE_DN);
LdapContext ctx = PortalLDAPUtil.getContext(companyId);
if (ctx == null) {
//查看LDAP验证是否是必须的
return authenticateRequired(
companyId, userId, emailAddress, FAILURE);
}
// Process LDAP auth search filter
String filter = PortalLDAPUtil.getAuthSearchFilter(
companyId, emailAddress, screenName, String.valueOf(userId));
try {
SearchControls cons = new SearchControls(
SearchControls.SUBTREE_SCOPE, 1, 0, null, false, false);
NamingEnumeration<SearchResult> enu = ctx.search(
baseDN, filter, cons);
if (enu.hasMore()) {
if (_log.isDebugEnabled()) {
_log.debug("Search filter returned at least one result");
}
SearchResult result = enu.next();
String fullUserDN = PortalLDAPUtil.getNameInNamespace(
companyId, result);
Attributes attrs = PortalLDAPUtil.getAttributes(
ctx, fullUserDN);
LDAPAuthResult ldapAuthResult = authenticate(
ctx, companyId, attrs, fullUserDN, password);
// Process LDAP failure codes
String errorMessage = ldapAuthResult.getErrorMessage();
if (errorMessage != null) {
if (errorMessage.indexOf(PrefsPropsUtil.getString(
companyId, PropsUtil.LDAP_ERROR_USER_LOCKOUT))
!= -1) {
throw new UserLockoutException();
}
else if (errorMessage.indexOf(PrefsPropsUtil.getString(
companyId, PropsUtil.LDAP_ERROR_PASSWORD_EXPIRED))
!= -1) {
throw new PasswordExpiredException();
}
}
if (!ldapAuthResult.isAuthenticated()) {
//查看LDAP验证是否是必须的
return authenticateRequired(
companyId, userId, emailAddress, FAILURE);
}
// Get user or create from LDAP
User user = PortalLDAPUtil.importLDAPUser(
companyId, ctx, attrs, password, true);
// Process LDAP success codes
String resultCode = ldapAuthResult.getResponseControl();
if (resultCode.equals(LDAPAuth.RESULT_PASSWORD_RESET)) {
UserLocalServiceUtil.updatePasswordReset(
user.getUserId(), true);
}
else if (
resultCode.equals(LDAPAuth.RESULT_PASSWORD_EXP_WARNING)) {
UserLocalServiceUtil.updatePasswordReset(
user.getUserId(), true);
}
}
else {
if (_log.isDebugEnabled()) {
_log.debug("Search filter did not return any results");
}
//查看LDAP验证是否是必须的
return authenticateRequired(
companyId, userId, emailAddress, DNE);
}
}
catch (Exception e) {
_log.error("Problem accessing LDAP server: " + e.getMessage());
//查看LDAP验证是否是必须的
if (authenticateRequired(
companyId, userId, emailAddress, FAILURE) == FAILURE) {
throw e;
}
}
finally {
ctx.close();
}
return SUCCESS;
}
4.Default Values选择你使用的DS服务 。
5.测试连接能否成功。这些参数要根据自已的服务来填写。

测试成功

/**
* 获得连接上下文
* @param companyId
* @return
* @throws Exception
*/
public static LdapContext getContext(long companyId) throws Exception {
//连接地址(优先取数据库中)
String baseProviderURL = PrefsPropsUtil.getString(
companyId, PropsUtil.LDAP_BASE_PROVIDER_URL);
//用户地址(优先取数据库中)
String pricipal = PrefsPropsUtil.getString(
companyId, PropsUtil.LDAP_SECURITY_PRINCIPAL);
//连接密码(优先取数据库中)
String credentials = PrefsPropsUtil.getString(
companyId, PropsUtil.LDAP_SECURITY_CREDENTIALS);
return getContext(companyId, baseProviderURL, pricipal, credentials);
}
public static LdapContext getContext(
long companyId, String providerURL, String pricipal,
String credentials)
throws Exception {
Properties env = new Properties();
env.put(
Context.INITIAL_CONTEXT_FACTORY,
PrefsPropsUtil.getString(
companyId, PropsUtil.LDAP_FACTORY_INITIAL));
env.put(Context.PROVIDER_URL, providerURL);
env.put(Context.SECURITY_PRINCIPAL, pricipal);
env.put(Context.SECURITY_CREDENTIALS, credentials);
LogUtil.debug(_log, env);
LdapContext ctx = null;
try {
ctx = new InitialLdapContext(env, null);
}
catch (Exception e) {
if (_log.isWarnEnabled()) {
_log.warn("Failed to bind to the LDAP server");
}
if (_log.isDebugEnabled()) {
_log.debug(e);
}
}
return ctx;
}
6.测试用户:Authentication search Filter验证过滤语句,现在是过滤email,Test LDAP Users这个按钮是不会调用这个过滤的,Import Search Filter测试用户过滤语句。下面是liferay数据与ldap数据一对应的关系。

测试成功

/**
* 测试取用户列表
* @param companyId
* @param ctx
* @param maxResults
* @return
* @throws Exception
*/
public static NamingEnumeration<SearchResult> getUsers(
long companyId, LdapContext ctx, int maxResults)
throws Exception {
String baseDN = PrefsPropsUtil.getString(
companyId, PropsUtil.LDAP_BASE_DN);
String userFilter = PrefsPropsUtil.getString(
companyId, PropsUtil.LDAP_IMPORT_USER_SEARCH_FILTER);
return getUsers(companyId, ctx, maxResults, baseDN, userFilter);
}
public static NamingEnumeration<SearchResult> getUsers(
long companyId, LdapContext ctx, int maxResults, String baseDN,
String userFilter)
throws Exception {
SearchControls cons = new SearchControls(
SearchControls.SUBTREE_SCOPE, maxResults, 0, null, false, false);
return ctx.search(baseDN, userFilter, cons);
}
7.测试取得用户组织,基本上同上就不详解,仅贴出成功画面和相关代码

/**
* 测试用户组织
* @param companyId
* @param ctx
* @param maxResults
* @return
* @throws Exception
*/
public static NamingEnumeration<SearchResult> getGroups(
long companyId, LdapContext ctx, int maxResults)
throws Exception {
String baseDN = PrefsPropsUtil.getString(
companyId, PropsUtil.LDAP_BASE_DN);
String groupFilter = PrefsPropsUtil.getString(
companyId, PropsUtil.LDAP_IMPORT_GROUP_SEARCH_FILTER);
return getGroups(companyId, ctx, maxResults, baseDN, groupFilter);
}
public static NamingEnumeration<SearchResult> getGroups(
long companyId, LdapContext ctx, int maxResults, String baseDN,
String groupFilter)
throws Exception {
SearchControls cons = new SearchControls(
SearchControls.SUBTREE_SCOPE, maxResults, 0, null, false, false);
return ctx.search(baseDN, groupFilter, cons);
}
8.导入导出配置:Import Enabled:是否导入,导入时密码为空 。 Import on Startup Enabled:启动导入。Import Interval:导入间隔时间,注意时间太短会影响性能。Export Enabled:是否导出, 在用户登陆时和修改用户信息时都会导出至LDAP但不导出密码,在修改时如果修改了密码才会把密码也导出进去,如果密码未导入至LDAP并且前面的 Required也勾选了,那么LDAP验证不会通过 。后面三个为导出的设置。

/**
* 从LDAP中导入用户
* @param companyId
* @param ctx
* @param attrs
* @param password
* @param importGroupMembership
* @return
* @throws Exception
*/
public static User importLDAPUser(
long companyId, LdapContext ctx, Attributes attrs, String password,
boolean importGroupMembership)
throws Exception {
AttributesTransformer attrsTransformer =
AttributesTransformerFactory.getInstance();
attrs = attrsTransformer.transformUser(attrs);
Properties userMappings = getUserMappings(companyId);
LogUtil.debug(_log, userMappings);
User defaultUser = UserLocalServiceUtil.getDefaultUser(companyId);
boolean autoPassword = false;
boolean updatePassword = true;
if (password.equals(StringPool.BLANK)) {
autoPassword = true;
updatePassword = false;
}
long creatorUserId = 0;
boolean passwordReset = false;
boolean autoScreenName = false;
String screenName = LDAPUtil.getAttributeValue(
attrs, userMappings.getProperty("screenName")).toLowerCase();
String emailAddress = LDAPUtil.getAttributeValue(
attrs, userMappings.getProperty("emailAddress"));
Locale locale = defaultUser.getLocale();
String firstName = LDAPUtil.getAttributeValue(
attrs, userMappings.getProperty("firstName"));
String middleName = LDAPUtil.getAttributeValue(
attrs, userMappings.getProperty("middleName"));
String lastName = LDAPUtil.getAttributeValue(
attrs, userMappings.getProperty("lastName"));
if (Validator.isNull(firstName) || Validator.isNull(lastName)) {
String fullName = LDAPUtil.getAttributeValue(
attrs, userMappings.getProperty("fullName"));
String[] names = LDAPUtil.splitFullName(fullName);
firstName = names[0];
middleName = names[1];
lastName = names[2];
}
int prefixId = 0;
int suffixId = 0;
boolean male = true;
int birthdayMonth = Calendar.JANUARY;
int birthdayDay = 1;
int birthdayYear = 1970;
String jobTitle = LDAPUtil.getAttributeValue(
attrs, userMappings.getProperty("jobTitle"));
long[] organizationIds = new long[0];
boolean sendEmail = false;
if (_log.isDebugEnabled()) {
_log.debug(
"Screen name " + screenName + " and email address " +
emailAddress);
}
if (Validator.isNull(screenName) || Validator.isNull(emailAddress)) {
if (_log.isWarnEnabled()) {
_log.warn(
"Cannot add user because screen name and email address " +
"are required");
}
return null;
}
User user = null;
try {
// Find corresponding portal user
String authType = PrefsPropsUtil.getString(
companyId, PropsUtil.COMPANY_SECURITY_AUTH_TYPE,
PropsValues.COMPANY_SECURITY_AUTH_TYPE);
if (authType.equals(CompanyConstants.AUTH_TYPE_SN)) {
user = UserLocalServiceUtil.getUserByScreenName(
companyId, screenName);
}
else {
user = UserLocalServiceUtil.getUserByEmailAddress(
companyId, emailAddress);
}
// Skip if is default user
if (user.isDefaultUser()) {
return user;
}
// Skip import if user fields has been already synced and if
// import is part of a scheduled import
Date ldapUserModifiedDate = null;
String modifiedDate = LDAPUtil.getAttributeValue(
attrs, "modifyTimestamp");
try {
DateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
ldapUserModifiedDate = dateFormat.parse(modifiedDate);
if (ldapUserModifiedDate.equals(user.getModifiedDate()) &&
autoPassword) {
if (_log.isDebugEnabled()) {
_log.debug(
"User is already syncronized, skipping user " +
user.getEmailAddress());
}
return user;
}
}
catch (ParseException pe) {
if (_log.isDebugEnabled()) {
_log.debug(
"Unable to parse LDAP modify timestamp " +
modifiedDate);
}
_log.debug(pe, pe);
}
Contact contact = user.getContact();
Calendar birthdayCal = CalendarFactoryUtil.getCalendar();
birthdayCal.setTime(contact.getBirthday());
birthdayMonth = birthdayCal.get(Calendar.MONTH);
birthdayDay = birthdayCal.get(Calendar.DATE);
birthdayYear = birthdayCal.get(Calendar.YEAR);
// User exists so update user information
if (updatePassword) {
user = UserLocalServiceUtil.updatePassword(
user.getUserId(), password, password, passwordReset,
true);
}
user = UserLocalServiceUtil.updateUser(
user.getUserId(), password, user.isPasswordReset(), screenName,
emailAddress, user.getLanguageId(), user.getTimeZoneId(),
user.getGreeting(), user.getComments(), firstName, middleName,
lastName, contact.getPrefixId(), contact.getSuffixId(),
contact.getMale(), birthdayMonth, birthdayDay, birthdayYear,
contact.getSmsSn(), contact.getAimSn(), contact.getIcqSn(),
contact.getJabberSn(), contact.getMsnSn(), contact.getSkypeSn(),
contact.getYmSn(), jobTitle, user.getOrganizationIds());
if (ldapUserModifiedDate != null) {
UserLocalServiceUtil.updateModifiedDate(
user.getUserId(), ldapUserModifiedDate);
}
}
catch (NoSuchUserException nsue) {
// User does not exist so create
}
if (user == null) {
try {
if (_log.isDebugEnabled()) {
_log.debug("Adding user to portal " + emailAddress);
}
user = UserLocalServiceUtil.addUser(
creatorUserId, companyId, autoPassword, password, password,
autoScreenName, screenName, emailAddress, locale, firstName,
middleName, lastName, prefixId, suffixId, male,
birthdayMonth, birthdayDay, birthdayYear, jobTitle,
organizationIds, sendEmail);
}
catch (Exception e){
_log.error(
"Problem adding user with screen name " + screenName +
" and email address " + emailAddress,
e);
}
}
// Import user groups and membership
if (importGroupMembership && (user != null)) {
String userMappingsGroup = userMappings.getProperty("group");
if (userMappingsGroup != null) {
Attribute attr = attrs.get(userMappingsGroup);
if (attr != null){
_importGroupsAndMembershipFromLDAPUser(
companyId, ctx, user.getUserId(), attr);
}
}
}
return user;
}
/**
* 将用户导出至LDAP
* @param user
* @throws Exception
*/
public static void exportToLDAP(User user) throws Exception {
long companyId = user.getCompanyId();
if (!isAuthEnabled(companyId) || !isExportEnabled(companyId)) {
return;
}
LdapContext ctx = getContext(companyId);
if (ctx == null) {
return;
}
Properties userMappings = getUserMappings(companyId);
Binding binding = getUser(user.getCompanyId(), user.getScreenName());
String name = StringPool.BLANK;
if (binding == null) {
// Generate full DN based on user DN
StringMaker sm = new StringMaker();
sm.append(userMappings.getProperty("screenName"));
sm.append(StringPool.EQUAL);
sm.append(user.getScreenName());
sm.append(StringPool.COMMA);
sm.append(getUsersDN(companyId));
name = sm.toString();
// Create new user in LDAP
LDAPUser ldapUser = (LDAPUser)Class.forName(
PropsValues.LDAP_USER_IMPL).newInstance();
ldapUser.setUser(user);
ctx.bind(name, ldapUser);
}
else {
// Modify existing LDAP user record
name = getNameInNamespace(companyId, binding);
Modifications mods = Modifications.getInstance();
if (user.isPasswordModified() &&
Validator.isNotNull(user.getPasswordUnencrypted())) {
mods.addItem(
userMappings.getProperty("password"),
user.getPasswordUnencrypted());
}
mods.addItem(
userMappings.getProperty("emailAddress"),
user.getEmailAddress());
ModificationItem[] modItems = mods.getItems();
ctx.modifyAttributes(name, modItems);
}
ctx.close();
}
9.Use LDAP Password Policy:是使用LDAP的密码策略,这个主要用在验证方面,不推荐使用。

本文介绍如何在Liferay中集成LDAP服务,包括安装配置LDAP服务器、客户端工具的选择及使用、Liferay中LDAP验证的配置流程、连接测试、用户及组织数据同步等关键步骤。
2652

被折叠的 条评论
为什么被折叠?



