Java向Samba Active Directory添加用户时名称显示异常求助
问题:向Samba AD添加用户后,用户名显示为$BE23343...异常字符串
通过Java编写的图形界面程序向Samba Active Directory添加用户时,操作可正常执行,但用户在AD中显示的名称为$BE23343...这类随机异常字符串。以下是相关代码:
import javax.naming.*; import javax.naming.directory.*; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.Hashtable; public class ADManagerUI extends JFrame { private static final long serialVersionUID = 1L; private JTextField cnField; private JTextField snField; private JTextField uidField; private JTextField passwordField; private JTextField mailField; private JTextField displayNameField; private JTextField descriptionField; private JButton addButton; private JButton deleteButton; private JButton modifyButton; public ADManagerUI() { // 初始化窗口 setTitle("AD用户管理器"); setSize(600, 400); setLocationRelativeTo(null); setDefaultCloseOperation(EXIT_ON_CLOSE); // 创建文本框和标签 JLabel cnLabel = new JLabel("全名:"); cnField = new JTextField(20); JLabel snLabel = new JLabel("姓氏:"); snField = new JTextField(20); JLabel uidLabel = new JLabel("用户名:"); uidField = new JTextField(20); JLabel passwordLabel = new JLabel("密码:"); passwordField = new JTextField(20); JLabel mailLabel = new JLabel("邮箱地址:"); mailField = new JTextField(20); JLabel displayNameLabel = new JLabel("显示名称:"); displayNameField = new JTextField(20); JLabel descriptionLabel = new JLabel("描述:"); descriptionField = new JTextField(20); // 创建按钮 addButton = new JButton("添加用户"); deleteButton = new JButton("删除用户"); modifyButton = new JButton("修改用户"); // 将文本框和标签添加到窗口 setLayout(new GridBagLayout()); GridBagConstraints constraints = new GridBagConstraints(); constraints.anchor = GridBagConstraints.WEST; constraints.insets = new Insets(5, 5, 5, 5); constraints.gridx = 0; constraints.gridy = 0; add(cnLabel, constraints); constraints.gridx = 1; add(cnField, constraints); constraints.gridx = 0; constraints.gridy = 1; add(snLabel, constraints); constraints.gridx = 1; add(snField, constraints); constraints.gridx = 0; constraints.gridy = 2; add(uidLabel, constraints); constraints.gridx = 1; add(uidField, constraints); constraints.gridx = 0; constraints.gridy = 3; add(passwordLabel, constraints); constraints.gridx = 1; add(passwordField, constraints); constraints.gridx = 0; constraints.gridy = 4; add(mailLabel, constraints); constraints.gridx = 1; add(mailField, constraints); constraints.gridx = 0; constraints.gridy = 5; add(displayNameLabel, constraints); constraints.gridx = 1; add(displayNameField, constraints); constraints.gridx = 0; constraints.gridy = 6; add(descriptionLabel, constraints); constraints.gridx = 1; add(descriptionField, constraints); // 将按钮添加到窗口 constraints.gridx = 0; constraints.gridy = 8; add(addButton, constraints); constraints.gridx = 1; add(deleteButton, constraints); constraints.gridx = 2; add(modifyButton, constraints); // 为按钮添加监听器 addButton.addActionListener(new AddButtonListener()); deleteButton.addActionListener(new DeleteButtonListener()); modifyButton.addActionListener(new ModifyButtonListener()); } // 内部类处理"添加"按钮点击事件 class AddButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { // LDAP服务器连接信息 String ldapAdServer = "ldap://serveur.domaine.com"; String ldapUsername = "cn=admin,dc=domaine,dc=com"; String ldapPassword = "mot_de_passe"; // 新用户信息 String cn = cnField.getText(); String sn = snField.getText(); String uid = uidField.getText(); String password = passwordField.getText(); String mail = mailField.getText(); String displayName = displayNameField.getText(); String description = descriptionField.getText(); // 连接LDAP服务器 Hashtable<String, Object> env = new Hashtable<String, Object>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, ldapAdServer); env.put(Context.SECURITY_PRINCIPAL, ldapUsername); env.put(Context.SECURITY_CREDENTIALS, ldapPassword); try { // 创建LDAP上下文 DirContext ctx = new InitialDirContext(env); // 创建新用户条目 Attributes attrs = new BasicAttributes(); Attribute objClasses = new BasicAttribute("objectClass"); objClasses.add("top"); objClasses.add("person"); objClasses.add("organizationalPerson"); objClasses.add("user"); attrs.put(objClasses); attrs.put(new BasicAttribute("cn", cn)); attrs.put(new BasicAttribute("sn", sn)); attrs.put(new BasicAttribute("uid", uid)); attrs.put(new BasicAttribute("userPassword", password)); attrs.put(new BasicAttribute("mail", mail)); attrs.put(new BasicAttribute("displayName", displayName)); attrs.put(new BasicAttribute("description", description)); String dn = "cn=" + cn + ",ou=utilisateurs,dc=domaine,dc=com"; ctx.createSubcontext(dn, attrs); ctx.close(); JOptionPane.showMessageDialog(null, "用户添加成功!"); } catch (NamingException ex) { ex.printStackTrace(); JOptionPane.showMessageDialog(null, "添加用户时出错!"); } } } // 补充缺失的监听器实现 class DeleteButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) {} } class ModifyButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) {} } public static void main(String[] args) { ADManagerUI adUI = new ADManagerUI(); adUI.setVisible(true); } }
问题原因分析
缺失AD核心属性
sAMAccountName:
Samba AD和Windows AD都依赖sAMAccountName作为用户的登录标识符和显示名称的核心属性。当前代码仅设置了LDAP标准属性uid,但AD不会自动将uid映射为sAMAccountName,当该属性缺失时,AD会自动生成一个以$开头的随机字符串作为默认值,这就是你看到的异常显示内容。密码属性设置错误:
AD不使用userPassword存储密码,而是使用UnicodePwd,且需要特定格式:密码必须用双引号包裹,再转换为UTF-16LE编码的字节数组。直接设置明文userPassword会导致密码无法正常生效。
修复方案
修改AddButtonListener中的属性设置逻辑,添加sAMAccountName并修复密码处理:
// 内部类处理"添加"按钮点击事件 class AddButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { // LDAP服务器连接信息 String ldapAdServer = "ldap://serveur.domaine.com"; String ldapUsername = "cn=admin,dc=domaine,dc=com"; String ldapPassword = "mot_de_passe"; // 新用户信息 String cn = cnField.getText(); String sn = snField.getText(); String uid = uidField.getText(); // 建议sAMAccountName与uid保持一致,需符合AD命名规则 String samAccountName = uid; String password = passwordField.getText(); String mail = mailField.getText(); String displayName = displayNameField.getText(); String description = descriptionField.getText(); // 连接LDAP服务器 Hashtable<String, Object> env = new Hashtable<String, Object>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, ldapAdServer); env.put(Context.SECURITY_PRINCIPAL, ldapUsername); env.put(Context.SECURITY_CREDENTIALS, ldapPassword); // 设置认证方式 env.put(Context.SECURITY_AUTHENTICATION, "simple"); // 若AD要求SSL连接,需开启以下配置并使用ldaps://地址 // env.put("java.naming.ldap.factory.socket", "javax.net.ssl.SSLSocketFactory"); try { // 创建LDAP上下文 DirContext ctx = new InitialDirContext(env); // 创建新用户条目 Attributes attrs = new BasicAttributes(); Attribute objClasses = new BasicAttribute("objectClass"); objClasses.add("top"); objClasses.add("person"); objClasses.add("organizationalPerson"); objClasses.add("user"); attrs.put(objClasses); attrs.put(new BasicAttribute("cn", cn)); attrs.put(new BasicAttribute("sn", sn)); attrs.put(new BasicAttribute("uid", uid)); // 添加AD必需的sAMAccountName属性 attrs.put(new BasicAttribute("sAMAccountName", samAccountName)); attrs.put(new BasicAttribute("mail", mail)); attrs.put(new BasicAttribute("displayName", displayName)); attrs.put(new BasicAttribute("description", description)); // 处理AD密码:双引号包裹后转UTF-16LE编码 String quotedPassword = "\"" + password + "\""; byte[] unicodePassword = quotedPassword.getBytes("UTF-16LE"); attrs.put(new BasicAttribute("UnicodePwd", unicodePassword)); // 可选:设置用户为启用状态(512为启用,514为禁用) attrs.put(new BasicAttribute("userAccountControl", "512")); String dn = "cn=" + cn + ",ou=utilisateurs,dc=domaine,dc=com"; ctx.createSubcontext(dn, attrs); ctx.close(); JOptionPane.showMessageDialog(null, "用户添加成功!"); } catch (Exception ex) { ex.printStackTrace(); JOptionPane.showMessageDialog(null, "添加用户时出错:" + ex.getMessage()); } } }
额外注意事项
- sAMAccountName命名规则:长度不超过20字符,不能包含
/ \ [ ] : ; | = , + * ? < >等特殊字符。 - 加密连接要求:设置
UnicodePwd时,AD通常要求使用LDAPS(端口636)或StartTLS加密连接,否则会抛出操作不允许的异常。 - 用户状态控制:默认创建的用户可能处于禁用状态,通过
userAccountControl属性可设置启用/禁用状态。
内容的提问来源于stack exchange,提问作者bertrand pacode
相关产品推荐
相关产品推荐

