3

ユーザーが Active Directory で自分のパスワードをリセットできる Web アプリを開発しています。管理者としてバインドして実行しており、正常に動作しますが、ディレクトリ ポリシー (再利用履歴、文字など) が適用されていません。現在のパスワードがないため、ユーザーとしてバインドできません。

Active Directoryでそれを行うためにWindows 2008 R2 SP1で導入されたLDAP_SERVER_POLICY_HINTSコントロールについて読み、Spring LDAPを使用してそれを作成した人を見つけました

私は UnboundID を使用しており、そのための標準コントロールは出荷されていないため、独自のコントロール クラスを作成する必要があると考えました。文書化された OID は 1.2.840.113556.1.4.2239 で、値は {48, 3, 2, 1, 1} です。

public class PolicyHintsControl extends Control {

    private static final long serialVersionUID = 1L;

    public final static String LDAP_SERVER_POLICY_HINTS_OID = "1.2.840.113556.1.4.2066";

    public final static byte[] LDAP_SERVER_POLICY_HINTS_DATA = { 48,
            (byte) 132, 0, 0, 0, 3, 2, 1, 1 };

    public PolicyHintsControl() {
        super(LDAP_SERVER_POLICY_HINTS_OID, false, new ASN1OctetString(
                LDAP_SERVER_POLICY_HINTS_DATA));
    }

    @Override
    public String getControlName() {
        return "LDAP Server Policy Hints Control";
    }

    @Override
    public void toString(StringBuilder buffer) {
        buffer.append("LDAPServerPolicyHints(isCritical=");
        buffer.append(isCritical());
        buffer.append(')');
    }
}

そこで、次のように変更リクエストにこの新しいコントロールを追加しました。

public static void main(String[] args) throws Exception {

    final String host = "ldap.example.com";
    final int port = 636;
    String adminDn = "admin@example.com";
    String adminPassword = "passwd";
    String userDn = "CN=user,ou=people,dc=example,dc=com";
    String userPassword = "passwd";
    String keystoreFile = "/path/to/keystore.jks";
    String keystorePassword = "passwd";

    String passwordAttribute = "unicodePwd";

    //Password change requires SSL
    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    keyStore.load(new FileInputStream(keystoreFile), keystorePassword.toCharArray());
    TrustManagerFactory factory = TrustManagerFactory.getInstance("x509");
    factory.init(keyStore);
    final SSLUtil sslUtil = new SSLUtil(factory.getTrustManagers());
    SSLSocketFactory socketFactory = sslUtil.createSSLSocketFactory();
    Debug.setEnabled(true);

    // Connect as the configured administrator
    LDAPConnection ldapConnection = new LDAPConnection(socketFactory, host,
            port, adminDn, adminPassword);
    // Set password in AD format
    final String newQuotedPassword = "\"" + userPassword + "\"";
    final byte[] newPasswordBytes = newQuotedPassword.getBytes("UTF-16LE");
    String encryptedNewPwd = new String(newPasswordBytes);
    //Build modifications array and request
    final ArrayList<Modification> modifications = new ArrayList<Modification>();
    modifications.add(new Modification(ModificationType.REPLACE,
            passwordAttribute, encryptedNewPwd));
    ModifyRequest modifyRequest = new ModifyRequest(userDn, modifications);
    //Add the policy hints control
    modifyRequest.addControl(new PolicyHintsControl());
    //Modify already
    ldapConnection.modify(modifyRequest);
    ldapConnection.close();
}

次の例外が発生します。

Exception in thread "main" LDAPException(resultCode=53 (unwilling to perform), errorMessage='0000052D: SvcErr: DSID-031A120C, problem 5003 (WILL_NOT_PERFORM), data 0
        ', diagnosticMessage='0000052D: SvcErr: DSID-031A120C, problem 5003 (WILL_NOT_PERFORM), data 0
        ')

もう少し調査した結果、Windows 2012 には、OID を 1.2.840.113556.1.4.2066 に変更し、古い OID を廃止する同じコントロールの別の更新プログラムがあることがわかりました。

このアプリは任意のバージョンの AD で構成できるため、すべてのシナリオ (Windows 2012、Windows 2008 R2 SP1 など) を適切に処理したいと考えています。私の質問は次のとおりです。

  1. UnboundID でこれを成功させた人はいますか?
  2. 変更要求の前にコントロールが利用可能かどうかを知る方法はありますか?
  3. 同じコントロールの異なるバージョンの AD の異なる OID を処理する最良の方法は何でしょうか? 同じクラスか違うクラスか?
4

1 に答える 1

4

私は Microsoft 固有のコントロールにあまり詳しくないので、そこに多くの助けを提供することはできませんが、あなたはすでに正しい方向に進んでいるようです. この場合、実際にはコントロールが期待どおりに機能しているように見えますが、パスワードの強度が十分でないため、サーバーはパスワードを拒否しています。

Active Directory は、このようなことを理解するのがいかに難しいかという点で本当にひどいものですが、その秘密は診断メッセージに示されている "0000052D" にあります。これは、10 進数の 1325 である Active Directory システム エラー コード 0x52D への参照です。システム エラー コードは、http: //msdn.microsoft.com/en-us/library/windows/desktop/ms681381(v=vs.85 .aspx、この場合、「システム エラー コード (1300-1699)」リンクに従う必要があります ( http://msdn.microsoft.com/en-us/library/windows/desktop/ms681385(v=vs .85).aspxそのエラー コードのテキストには、「パスワードを更新できません。新しいパスワードに指定された値は、ドメインの長さ、複雑さ、または履歴の要件を満たしていません。」と表示されます。使用しようとしているコントロールのポイントは、サーバーに新しいパスワードの品質チェックを実行させることであるように思われるため、期待どおりに機能しているようです。より強力なパスワードを使用する場合 (たとえば、パスワードを長くする、大文字/数字/記号を含めるなど)、おそらくサーバーはそれを受け入れます。

サーバーがサポートするコントロールを特定する方法についての質問に関しては、サーバーのルート DSE を取得し、supportedControls 属性で報告された OID を確認する方法があります。UnboundID LDAP SDK for Java を使用すると、LDAPConnection.getRootDSE メソッドを使用してルート DSE を取得し、次に RootDSE.supportsControl メソッドを使用してサーバーが指定されたコントロールをサポートしているかどうかを判断できるため、これが非常に簡単になります。

同じクラスまたは異なるクラスで異なる OID を処理するかどうかについてのあなたの質問に関しては、それは何よりもスタイルの問題です。新しい OID を持つコントロールでも値に別のエンコーディングが使用されている場合は、別のクラスを作成することをお勧めします。値のエンコーディングが両方の OID で同じである場合、それはおそらく個人的な好みの問題ですが、それらを別のクラスにする場合でも、同じコードを 2 つの異なる場所に置くよりも、コードの大部分を共通に保つ方がよいでしょう。 .

于 2014-01-15T17:39:02.703 に答える