package org.synyx.urlaubsverwaltung.security.ldap;

import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.DirContextOperations;

import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import java.util.ArrayList;
import java.util.List;

import static java.util.Arrays.asList;
import static org.springframework.util.StringUtils.hasText;

/**
 * Maps LDAP attributes to {@link LdapUser} class.
 */
public class LdapUserMapper implements AttributesMapper<LdapUser> {

    private final DirectoryServiceSecurityProperties directoryServiceSecurityProperties;

    LdapUserMapper(DirectoryServiceSecurityProperties directoryServiceSecurityProperties) {
        this.directoryServiceSecurityProperties = directoryServiceSecurityProperties;
    }

    @Override
    public LdapUser mapFromAttributes(Attributes attributes) throws NamingException {

        final String username = extractAttribute(attributes, directoryServiceSecurityProperties.getIdentifier());
        final String firstName = extractAttribute(attributes, directoryServiceSecurityProperties.getFirstName());
        final String lastName = extractAttribute(attributes, directoryServiceSecurityProperties.getLastName());
        final String email = extractAttribute(attributes, directoryServiceSecurityProperties.getMailAddress());

        final List<String> groups = new ArrayList<>();
        final Attribute memberOfAttribute = attributes.get("memberOf");
        if (memberOfAttribute != null) {
            final NamingEnumeration<?> groupNames = memberOfAttribute.getAll();
            while (groupNames.hasMoreElements()) {
                groups.add((String) groupNames.nextElement());
            }
        }

        return new LdapUser(username, firstName, lastName, email, groups);
    }

    LdapUser mapFromContext(DirContextOperations ctx) throws UnsupportedMemberAffiliationException {

        final String username = extractAttribute(ctx, directoryServiceSecurityProperties.getIdentifier());
        final String firstName = extractAttribute(ctx, directoryServiceSecurityProperties.getFirstName());
        final String lastName = extractAttribute(ctx, directoryServiceSecurityProperties.getLastName());
        final String email = extractAttribute(ctx, directoryServiceSecurityProperties.getMailAddress());

        List<String> memberOf = new ArrayList<>();
        final String memberOfProperty = directoryServiceSecurityProperties.getFilter().getMemberOf();
        if (hasText(memberOfProperty)) {
            memberOf = asList(ctx.getStringAttributes("memberOf"));

            if (!memberOf.contains(memberOfProperty)) {
                throw new UnsupportedMemberAffiliationException("User '" + username + "' is not a member of '" + memberOfProperty + "'");
            }
        }

        return new LdapUser(username, firstName, lastName, email, memberOf);
    }

    private String extractAttribute(Attributes attributes, String identifier) throws NamingException {
        final Attribute attribute = attributes.get(identifier);
        if (attribute == null) {
            throw new InvalidSecurityConfigurationException("Can not retrieve the attribute using the identifier '" + identifier + "'");
        }

        final String attributeValue = (String) attribute.get();
        if (attributeValue == null || attributeValue.isBlank()) {
            throw new InvalidSecurityConfigurationException("The attribute using the identifier '" + identifier + "' is blank or null");
        }

        return attributeValue;
    }

    private String extractAttribute(DirContextOperations dirContextOperations, String identifier) {
        final String attribute = dirContextOperations.getStringAttribute(identifier);
        if (attribute == null || attribute.isBlank()) {
            throw new InvalidSecurityConfigurationException("The attribute using the identifier '" + identifier + "' is blank or null");
        }
        return attribute;
    }
}

@@ -45,16 +45,41 @@
 .ldap;%0A%0A
+import org.slf4j.Logger;%0A
 import o
@@ -419,26 +419,128 @@
 ava.
-util.Arrays.asList
+lang.invoke.MethodHandles.lookup;%0Aimport static java.util.Arrays.asList;%0Aimport static org.slf4j.LoggerFactory.getLogger
 ;%0Aim
@@ -722,24 +722,98 @@
 dapUser%3E %7B%0A%0A
+    private static final Logger LOG = getLogger(lookup().lookupClass());%0A%0A
     private 
@@ -2936,32 +2936,124 @@
 rOfProperty)) %7B%0A
+                LOG.error(%22User '%7B%7D' is not a member of '%7B%7D'%22, username, memberOfProperty);%0A
                 
@@ -3475,32 +3475,127 @@
 bute == null) %7B%0A
+            LOG.error(%22Can not retrieve the attribute using the identifier '%7B%7D'%22, identifier);%0A
             thro
@@ -3848,32 +3848,127 @@
 ue.isBlank()) %7B%0A
+            LOG.error(%22The attribute using the identifier '%7B%7D' is blank or null%22, identifier);%0A
             thro
@@ -4371,32 +4371,127 @@
 te.isBlank()) %7B%0A
+            LOG.error(%22The attribute using the identifier '%7B%7D' is blank or null%22, identifier);%0A
             thro

Add error logging for ldap InvalidSecurityConfigurationException