pingidentity / ldapsdk

UnboundID LDAP SDK for Java
Other
334 stars 81 forks source link

Unable to login with AdditionalBindCredentials when certain OperationTypes are part of AuthenticationRequiredOperationTypes (Supressing Anonymous Connections) #155

Closed Fabian95qw closed 11 months ago

Fabian95qw commented 11 months ago

Good Day.

I'm working on a simple implementation of an LDAP Server, that exposes an adressbook which otherwise is only reachable via REST, so it can acessed from some hardware phones via LDAP.

I'm using the InMemoryDirectoryServer, and i just periodically sync the adressbook with the ldap server to keep it up to date.

This all is working perfectly.

Due to security concerns i want to block anonymous connections to the LDAP Server, and allow only a connection with a valid Login and Password.

I spent the best of 3 hours trying to find a solution, in the end i couldn't find much that helped me. After looking trough the functions, i found one thats promising, the "InMemoryDirectoryServerConfig.setAuthenticationRequiredOperationTypes"

I tried adding all But the BIND and UNBIND operations to the "setAuthenticationRequiredOperationTypes" in order to block anonymous connections, which worked.

On my anonymous connections i can still connect, but get a [2023-10-26T09:58:39,832] [TRACE] [] [] [26/Oct/2023:09:58:39 +0200] SEARCH RESULT conn=4 op=1 msgID=23 resultCode=50 diagnosticMessage="The server has been configured to only allow search operations for authenticated clients." etime=0.530 entriesReturned=0

Now if i try to use my Login set by "addAdditionalBindCredentials" for example "Config.addAdditionalBindCredentials("cn=Test", "Test123");

The Server respons with a [26/Oct/2023:10:00:19 +0200] BIND RESULT conn=5 op=0 msgID=24 resultCode=49 diagnosticMessage="Unable to bind as user 'cn=Test' because no such entry exists in the server." etime=0.047

If i don't restrict the Operations with "setAuthenticationRequiredOperationTypes" the AdditionalBindCredentials work normally.

I'm not suer if this is a bug, or i'm misunderstanding how it works.

Any help would be appreciated!

Sincerely Fabian95qw

dirmgr commented 11 months ago

I've looked into this, but have not been able to reproduce it for myself. Could you please provide a simple test program that demonstrates the problem?

Fabian95qw commented 11 months ago

Strangely enough, when i cull the code to a minimal, it works?

This is the example i prepared:

public class Main
{

    public static void main(String[] args) throws Exception
    {
        InMemoryDirectoryServerConfig Config = null;
        InMemoryListenerConfig ListenerConfig = null;
        InMemoryDirectoryServer Server = null;

        Integer Port = 3890;
        String Login = "Test";
        String Password = "Test123";

        System.out.println("Setting up LDAP Server on Port: " + Port);
        Config = new InMemoryDirectoryServerConfig("dc=starface,dc=pbx");
        ListenerConfig = InMemoryListenerConfig.createLDAPConfig("LDAP", Port);
        Config.setAccessLogHandler(new Handler()
        {

            @Override
            public void publish(LogRecord record)
            {
                System.out.println(record.getMessage());
            }

            @Override
            public void flush()
            {

            }

            @Override
            public void close() throws SecurityException
            {

            }
        });

        List<OperationType> BlockAnon = new ArrayList<OperationType>();
        BlockAnon.add(OperationType.ADD);
        BlockAnon.add(OperationType.COMPARE);
        BlockAnon.add(OperationType.DELETE);
        BlockAnon.add(OperationType.EXTENDED);
        BlockAnon.add(OperationType.MODIFY);
        BlockAnon.add(OperationType.MODIFY_DN);
        BlockAnon.add(OperationType.SEARCH);

        Config.setAuthenticationRequiredOperationTypes(BlockAnon);
        Config.addAdditionalBindCredentials("cn=" + Login, Password);

        Config.setListenerConfigs(ListenerConfig);

        Server = new InMemoryDirectoryServer(Config);
        Entry Root = new Entry("dn: dc=starface,dc=pbx", "objectClass: top", "objectClass: domain", "dc: starface");
        System.out.println("Creating Root: " + Root.toLDIFString());

        Server.add(Root);
        Server.startListening();
        System.out.println("LDAP Server is up!");
    }
}

The Original that doesn't work:


    private IRuntimeEnvironment context = null;
    private Logger log = null;
    private InMemoryDirectoryServerConfig Config = null;
    private InMemoryListenerConfig ListenerConfig = null;
    private InMemoryDirectoryServer Server = null;
    private boolean isRunning=false;

    private Integer Port = -1;
    private Map<String, String> Foldermapping=null;
    private String Login="";
    private String Password="";
    private Integer STARFACE_ACCOUNT;
    private boolean SSL = false;

    private static File Keystore=new File("/opt/tomcat/ssl/tomcat.keystore");
    private static String Keypass="changeit";
    private static File Truststore = new File("/opt/tomcat/webapps/localhost/starface/WEB-INF/truststore.jks");

    public LDAPServer(Integer Port, String Login, String Password,Integer STARFACE_ACCOUNT, Map<String, String> Foldermapping, boolean SSL, IRuntimeEnvironment context)
    {
        this.context=context;
        this.log=context.getLog();
        this.Port=Port;
        this.Login=Login;
        this.Password=Password;
        this.STARFACE_ACCOUNT=STARFACE_ACCOUNT;
        this.Foldermapping=Foldermapping;
        this.SSL=SSL;
        log.debug("STARFACE LDAP Interface!");
    }

    public void start() throws LDAPException, InterruptedException, LDIFException
    {
        log.debug("Setting up LDAP Server on Port: " + Port);
         // Create a base configuration for the server.
        Config = new InMemoryDirectoryServerConfig("dc=starface,dc=pbx");

        if(SSL)
        {
            try 
            {
                SSLUtil SSL = new SSLUtil(
                        new KeyStoreKeyManager(Keystore, Keypass.toCharArray()), 
                        new TrustStoreTrustManager(Truststore));
                ListenerConfig = InMemoryListenerConfig.createLDAPSConfig("LDAPS", SSL.createSSLServerSocketFactory());
            } 
            catch (GeneralSecurityException e)
            {
                LogHelper.EtoStringLog(log, e);
                return;
            }

        }
        else
        {
            ListenerConfig  = InMemoryListenerConfig.createLDAPConfig("LDAP", Port);
        }

        Config.setAccessLogHandler(new LDAPLogHandler(log));

        List<OperationType> BlockAnon = new ArrayList<OperationType>();
        BlockAnon.add(OperationType.ADD);
        BlockAnon.add(OperationType.COMPARE);
        BlockAnon.add(OperationType.DELETE);
        BlockAnon.add(OperationType.EXTENDED);
        BlockAnon.add(OperationType.MODIFY);
        BlockAnon.add(OperationType.MODIFY_DN);
        BlockAnon.add(OperationType.SEARCH);
        Config.setAuthenticationRequiredOperationTypes(BlockAnon);
        Config.addAdditionalBindCredentials("cn="+Login, Password); 

        Config.setListenerConfigs(ListenerConfig);   
         // Create and start the server instance and populate it with an initial set
         // of data from an LDIF file.

        Server = new InMemoryDirectoryServer(Config);
           Entry Root = new Entry(
                     "dn: dc=starface,dc=pbx",
                     "objectClass: top",
                     "objectClass: domain",
                     "dc: starface");
           log.debug("Creating Root: " + Root.toLDIFString());

           Server.add(Root);     

         // Start the server so it will accept client connections.
        Server.startListening();

        log.debug("LDAP Server is up!");
         isRunning=true;
    }

I copied down the libraries from the pbx so the local version is using the exact same libraries. The only code the local version does not have is the SSL Config, but i also tested it without the SSL config on the PBX and the error persisted.

I might have broke something when passing the Login and Password from the frontend to this function by accident. I'll have to check my other code.

Fabian95qw commented 11 months ago

Yes, sorry, i broke some code with the Login and Password passtrough from the UI, while testing LDAP stuff, without noticing. It's properly working now that i fixed that.