Единый вход LDAP для запросов Active Directory в Java - PullRequest
0 голосов
/ 13 мая 2019

Прежде всего, я надеюсь, что мой вопрос понятен. Я не очень знаком с терминами Active Directory, LDAP и Kerberos.

Я работаю над приложением Java для рабочего стола. В приложении мы запускаем exe для получения информации о пользователе из Active Directory.

Все пользователи приложения входят в Active Directory.

Код exe (C ++):

#include "stdafx.h"

#define NERR_Success 0 /* Success */

#pragma comment(lib,"Wldap32.lib") //Winsock Library
#pragma comment(lib, "netapi32.lib")

const size_t newsize = 100;

//  Entry point for application
int main(int argc, char* argv[])
{
    PWCHAR hostName = NULL;
    LDAP* pLdapConnection = NULL;
    ULONG version = LDAP_VERSION3;
    ULONG getOptSuccess = 0;
    ULONG connectSuccess = 0;
    INT returnCode = 0;

    //resolve domain name
    DWORD dwLevel = 102;
    LPWKSTA_INFO_102 pBuf = NULL;
    NET_API_STATUS nStatus;

    nStatus = NetWkstaGetInfo(NULL, dwLevel, (LPBYTE *)&pBuf);
    wchar_t* region = pBuf->wki102_langroup;

    std::wstring dom(L"DC=");
    dom += (std::wstring(region));
    dom += std::wstring(L",DC=#,DC=#,DC=#");

    wchar_t* domain = (wchar_t*)dom.c_str(); // distinguishedName

    if (argc != 2) {
        printf("Usage: user2upn.exe <username>");
        exit(0);
    }

    std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
    std::wstring user = converter.from_bytes(argv[1]);

    LDAPMessage *pMsg = NULL, *e;
    std::wstring filter = L"(&(objectClass=User)(sAMAccountName=" + user + L"))";
    PWSTR  attrs[] = { L"mail", NULL };

    BerElement *ber;
    wchar_t *a, *dn;
    wchar_t **vals;
    int i;

    hostName = NULL;
    //  Initialize a session. LDAP_PORT is the default port, 389.
    pLdapConnection = ldap_init(hostName, LDAP_PORT);

    if (pLdapConnection == NULL)
    {
        //  Set the HRESULT based on the Windows error code.
        HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
        printf("ldap_init failed with 0x%x.\n", hr);
        goto error_exit;
    }
    //else
        //printf("ldap_init succeeded \n");

    //  Set the version to 3.0 (default is 2.0).
    returnCode = ldap_set_option(pLdapConnection,
        LDAP_OPT_PROTOCOL_VERSION,
        (void*)&version);

    if (returnCode != LDAP_SUCCESS){
        printf("SetOption Error:%0X\n", returnCode);
        goto error_exit;
    }
    // Connect to the server.
    connectSuccess = ldap_connect(pLdapConnection, NULL);

    if (connectSuccess != LDAP_SUCCESS){
        printf("ldap_connect failed with 0x%x.\n", connectSuccess);
        goto error_exit;
    }

    returnCode = ldap_bind_s(pLdapConnection, NULL, NULL,
        LDAP_AUTH_NEGOTIATE);
    if (returnCode != LDAP_SUCCESS)
        goto error_exit;

    int start = GetTickCount();
    // Perform the search request.
    returnCode = ldap_search_s(pLdapConnection,
        domain,
        LDAP_SCOPE_SUBTREE,
        (PWSTR)filter.c_str(),
        attrs,
        0,
        &pMsg
    );
    int end = GetTickCount();
    /* for each entry print out name + all attrs and values */
    for (e = ldap_first_entry(pLdapConnection, pMsg); e != NULL;
        e = ldap_next_entry(pLdapConnection, e)) {
        if ((dn = ldap_get_dn(pLdapConnection, e)) != NULL) {
            //printf("dn: %S\n", dn);
            ldap_memfree(dn);
        }
        for (a = ldap_first_attribute(pLdapConnection, e, &ber);
            a != NULL; a = ldap_next_attribute(pLdapConnection, e, ber)) {
            if ((vals = ldap_get_values(pLdapConnection, e, a)) != NULL) {
                for (i = 0; vals[i] != NULL; i++) {
                    printf("%S:%S\n", a, vals[i]);
                }
                ldap_value_free(vals);
            }
            ldap_memfree(a);
        }
        printf("\n");
    }   //  Normal cleanup and exit.
    ldap_unbind(pLdapConnection);
    return 0;

    //  On error cleanup and exit.
error_exit:
    ldap_unbind(pLdapConnection);
    return -1;
}

Я хочу сделать то же самое в Java. Мне удалось получить информацию о пользователях из Active Directory, но только после входа в систему с именем пользователя и паролем:

Мой код в Java:

package com.ldap.main;

import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;

public class App {

    public static void main(String[] args) throws NamingException {
        runWithSimpleAuth();
    }

    public static void runWithSimpleAuth() throws NamingException {
        final String ldapAdServer = "ldap://###";
        final String ldapSearchBase = "dc=#,dc=#,dc=#";

        final String ldapUsername = "username";
        final String ldapPassword = "password";

        final String ldapAccountToLookup = "somename";

        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_AUTHENTICATION, "simple");
        env.put(Context.SECURITY_PRINCIPAL, ldapUsername);
        env.put(Context.SECURITY_CREDENTIALS, ldapPassword);


        env.put("java.naming.ldap.attributes.binary", "objectSID");

        DirContext ctx = new InitialDirContext(env);

        App ldap = new App();
        SearchResult srLdapUser = ldap.findAccountByAccountName(ctx, ldapSearchBase, ldapAccountToLookup);
    }

    public SearchResult findAccountByAccountName(DirContext ctx, String ldapSearchBase, String accountName)
            throws NamingException {

        String searchFilter = "(&(objectClass=User)(sAMAccountName=" + accountName + "))";

        SearchControls searchControls = new SearchControls();
        searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);

        NamingEnumeration<SearchResult> results = ctx.search(ldapSearchBase, searchFilter, searchControls);

        SearchResult searchResult = null;
        if (results.hasMoreElements()) {
            searchResult = (SearchResult) results.nextElement();

            if (results.hasMoreElements()) {
                System.err.println("Matched multiple users for the accountName: " + accountName);
                return null;
            }
        }
        return searchResult;
    }
}

Как я могу пропустить шаг входа?

Что такое Java, эквивалентный этому ldap_bind_s(pLdapConnection, NULL, NULL, LDAP_AUTH_NEGOTIATE) вызову функции?

Спасибо!

1 Ответ

2 голосов
/ 14 мая 2019

Я уже сотворил магию для вас в моей библиотеке с открытым исходным кодом: JNDI DirContextSource . Все, что вам нужно предоставить, это имя конфигурации JAAS.

...