You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AD用户设下次登录需改密码时,LDAP改密码报错误49(子码773)求助

问题:AD用户设置「下次登录必须更改密码」时,LDAP修改密码失败

当AD用户账户被标记为「下次登录必须更改密码」时,通过LDAP执行密码修改操作会抛出以下错误:
cause: javax.naming.AuthenticationException: [LDAP: error code 49 - 80090308: LdapErr: DSID-0C090447, comment: AcceptSecurityContext error, data 773, v3839

LDAP错误子码773的含义是「用户必须重置密码」,但当前操作正是要完成密码重置。而未设置该标志时,以下代码可以正常修改密码:

public void updateUserPassword(String user, String oldPassword,
                               String newPassword) throws NamingException, LoginException {
    try {
        InitialDirContext ctx = this.getContext();

        String filter = "(&(objectClass=user)(sAMAccountName=" + user + "))";
        String baseDn = (String) this.getActiveDirectoryProps().get("baseDN_User");

        // Search for user entry
        SearchControls ctls = new SearchControls();
        ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        ctls.setReturningObjFlag(true);

        String[] returnAttrs = new String[3];
        returnAttrs[0] = "cn"; // Common Name
        returnAttrs[1] = "displayName";
        returnAttrs[2] = "description";

        NamingEnumeration<SearchResult> enumSearchResult = ctx.search(baseDn, filter, returnAttrs, ctls);


        if (enumSearchResult.hasMore()) {
            SearchResult result = enumSearchResult.next();
    
            DirContext userCtx = (DirContext) result.getObject();

            // Change the BindUser
            ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, userCtx.getNameInNamespace());
            ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, oldPassword);

            // Update password
            Attribute oldattr = new BasicAttribute("unicodePwd", toUnicodeBytes(oldPassword));
            Attribute newattr = new BasicAttribute("unicodePwd", toUnicodeBytes(newPassword));
            ModificationItem olditem = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, oldattr);
            ModificationItem newitem = new ModificationItem(DirContext.ADD_ATTRIBUTE, newattr);

            String dn = userCtx.getNameInNamespace();
            ctx.modifyAttributes(dn, new ModificationItem[]{olditem, newitem});
        }
        ctx.close();
    } catch (final NamingException nE) {
        //
    } catch (Exception E) {
       //
    } finally {
      //
    }
}

失败原因

核心问题在于用户账户状态与绑定权限冲突:

  • 当AD用户被标记为「下次登录必须改密码」时,账户处于受限状态,无法通过自身旧密码完成LDAP绑定操作(AD的安全机制限制)。
  • 当前代码中,搜索到用户后会尝试将LDAP上下文切换为该用户(用旧密码重新绑定),这一步会触发AD的校验,直接返回773错误,导致后续密码修改操作无法执行。

修改方案

需要使用拥有AD用户密码重置权限的管理员账户来执行操作,同时调整代码逻辑:

1. 移除用户自身绑定的代码

删除以下两行切换绑定用户的代码,确保初始的InitialDirContext是用管理员账户创建的(即getContext()方法返回管理员权限的上下文):

ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, userCtx.getNameInNamespace());
ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, oldPassword);

2. 优化密码修改逻辑(可选)

AD支持直接用REPLACE_ATTRIBUTE修改密码,替代原有的「移除旧密码+添加新密码」逻辑,代码更简洁:

// 替换原有的密码修改代码段
Attribute newPwdAttr = new BasicAttribute("unicodePwd", toUnicodeBytes(newPassword));
ModificationItem pwdModItem = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, newPwdAttr);
ctx.modifyAttributes(dn, new ModificationItem[]{pwdModItem});

3. 清除「下次登录必须改密码」标志

修改密码后,添加代码将用户的pwdLastSet属性设置为-1,清除强制改密码的标记:

// 在密码修改完成后添加这段代码
Attribute pwdLastSetAttr = new BasicAttribute("pwdLastSet", "-1");
ModificationItem pwdLastSetMod = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, pwdLastSetAttr);
ctx.modifyAttributes(dn, new ModificationItem[]{pwdLastSetMod});

内容的提问来源于stack exchange,提问作者windy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 21:46:06