Implemented mapping of LDAP username to email.

Change-Id: Ifb1d2969c6dfafe768b99524de8303277184a94d
diff --git a/full/Changes b/full/Changes
index 200fc74..b74fca3 100644
--- a/full/Changes
+++ b/full/Changes
@@ -1,5 +1,9 @@
 # version 0.67.1
 
+2022-05-12
+ - Implemented mapping of LDAP username to email
+
+
 # version 0.67
 
 2022-05-09
@@ -8,6 +12,7 @@
 2022-05-11
  - Changed the SQL script updating oauth2_client table
 
+
 # version 0.66
 
 2022-03-31
diff --git a/full/src/main/java/de/ids_mannheim/korap/authentication/KustvaktAuthenticationManager.java b/full/src/main/java/de/ids_mannheim/korap/authentication/KustvaktAuthenticationManager.java
index c135506..fefa17c 100644
--- a/full/src/main/java/de/ids_mannheim/korap/authentication/KustvaktAuthenticationManager.java
+++ b/full/src/main/java/de/ids_mannheim/korap/authentication/KustvaktAuthenticationManager.java
@@ -438,9 +438,9 @@
 		User unknown = null;
 		// just to make sure that the plain password does not appear anywhere in
 		// the logs!
-
-		System.out.printf("Debug: authenticateIdM: entering for '%s'...\n", username);
-
+		if (DEBUG){
+            jlog.debug("Debug: authenticateIdM: entering for '%s'...\n", username);
+		}
 		/**
 		 * wozu Apache Validatoren für User/Passwort für IdM/LDAP? siehe
 		 * validation.properties. Abgeschaltet 21.04.17/FB try {
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuTokenService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuTokenService.java
index c4dd257..786398f 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuTokenService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuTokenService.java
@@ -21,7 +21,11 @@
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import com.unboundid.ldap.sdk.LDAPException;
+
+import de.ids_mannheim.korap.authentication.LdapAuth3;
 import de.ids_mannheim.korap.config.Attributes;
+import de.ids_mannheim.korap.constant.AuthenticationMethod;
 import de.ids_mannheim.korap.encryption.RandomCodeGenerator;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.exceptions.StatusCodes;
@@ -262,6 +266,18 @@
 
         Set<AccessScope> accessScopes =
                 scopeService.convertToAccessScope(scopes);
+        
+        if (config.getOAuth2passwordAuthentication()
+                .equals(AuthenticationMethod.LDAP)) {
+            try {
+                username = LdapAuth3.getEmail(username, config.getLdapConfig());
+            }
+            catch (LDAPException e) {
+                throw new KustvaktException(StatusCodes.LDAP_BASE_ERRCODE,
+                        e.getExceptionMessage());
+            }
+        }
+        
         return createsAccessTokenResponse(scopes, accessScopes, clientId,
                 username, authenticationTime,
                 false);
diff --git a/full/src/test/java/de/ids_mannheim/korap/authentication/LdapAuth3Test.java b/full/src/test/java/de/ids_mannheim/korap/authentication/LdapAuth3Test.java
index c926579..65322d9 100644
--- a/full/src/test/java/de/ids_mannheim/korap/authentication/LdapAuth3Test.java
+++ b/full/src/test/java/de/ids_mannheim/korap/authentication/LdapAuth3Test.java
@@ -53,7 +53,7 @@
     }
 
     @AfterClass
-    public static void ShutDownDirectoryServer() {
+    public static void shutDownDirectoryServer() {
         server.shutDown(true);
     }
 
diff --git a/full/src/test/java/de/ids_mannheim/korap/authentication/LdapOAuth2Test.java b/full/src/test/java/de/ids_mannheim/korap/authentication/LdapOAuth2Test.java
new file mode 100644
index 0000000..48f6193
--- /dev/null
+++ b/full/src/test/java/de/ids_mannheim/korap/authentication/LdapOAuth2Test.java
@@ -0,0 +1,198 @@
+package de.ids_mannheim.korap.authentication;
+
+import static org.junit.Assert.assertEquals;
+
+import java.net.URI;
+import java.security.GeneralSecurityException;
+
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.http.entity.ContentType;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.net.HttpHeaders;
+import com.sun.jersey.api.client.ClientHandlerException;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.UniformInterfaceException;
+import com.unboundid.ldap.sdk.LDAPException;
+
+import de.ids_mannheim.korap.config.Attributes;
+import de.ids_mannheim.korap.config.FullConfiguration;
+import de.ids_mannheim.korap.constant.AuthenticationMethod;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.oauth2.constant.OAuth2ClientType;
+import de.ids_mannheim.korap.oauth2.dao.AccessTokenDao;
+import de.ids_mannheim.korap.oauth2.dao.OAuth2ClientDao;
+import de.ids_mannheim.korap.oauth2.dao.RefreshTokenDao;
+import de.ids_mannheim.korap.oauth2.entity.AccessToken;
+import de.ids_mannheim.korap.oauth2.entity.OAuth2Client;
+import de.ids_mannheim.korap.oauth2.entity.RefreshToken;
+import de.ids_mannheim.korap.utils.JsonUtils;
+import de.ids_mannheim.korap.web.controller.OAuth2TestBase;
+import de.ids_mannheim.korap.web.input.OAuth2ClientJson;
+
+public class LdapOAuth2Test extends OAuth2TestBase {
+
+    @Autowired
+    private FullConfiguration config;
+    @Autowired
+    private AccessTokenDao accessDao;
+    @Autowired
+    private RefreshTokenDao refreshDao;
+    @Autowired
+    private OAuth2ClientDao clientDao;
+    
+    private String testUserEmail = "testuser@example.com";
+    private String redirectUri = "https://client.com/redirect";
+
+    @BeforeClass
+    public static void startTestLDAPServer ()
+            throws LDAPException, GeneralSecurityException {
+        LdapAuth3Test.startDirectoryServer();
+
+    }
+
+    @AfterClass
+    public static void stopTestLDAPServer () {
+        LdapAuth3Test.shutDownDirectoryServer();
+    }
+
+    @Before
+    public void setLDAPAuthentication () {
+        config.setOAuth2passwordAuthentication(AuthenticationMethod.LDAP);
+    }
+
+    @After
+    public void resetAuthenticationMethod () {
+        config.setOAuth2passwordAuthentication(AuthenticationMethod.TEST);
+    }
+
+    @Test
+    public void testRequestTokenPasswordUnknownUser ()
+            throws KustvaktException {
+
+        ClientResponse response = requestTokenWithPassword(superClientId,
+                clientSecret, "unknown", "password");
+
+        assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
+
+        String entity = response.getEntity(String.class);
+        JsonNode node = JsonUtils.readTree(entity);
+
+        assertEquals(2023, node.at("/errors/0/0").asInt());
+        assertEquals(
+                "LDAP Authentication failed due to unknown user or password!",
+                node.at("/errors/0/1").asText());
+    }
+
+    @Test
+    public void testMapUsernameToEmail () throws KustvaktException {
+        ClientResponse response = requestTokenWithPassword(superClientId,
+                clientSecret, "testUser", "password");
+        JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+
+        
+        String accessToken = node.at("/access_token").asText();
+        AccessToken accessTokenObj = accessDao.retrieveAccessToken(accessToken);
+        assertEquals(testUserEmail, accessTokenObj.getUserId());
+
+        String refreshToken = node.at("/refresh_token").asText();
+        RefreshToken rt = refreshDao.retrieveRefreshToken(refreshToken);
+        assertEquals(testUserEmail, rt.getUserId());
+        
+        testRegisterPublicClient(accessToken);
+        node = testRegisterConfidentialClient(accessToken);
+        String clientId = node.at("/client_id").asText();
+        String clientSecret = node.at("/client_secret").asText();
+        
+        testRequestTokenWithAuthorization(clientId, clientSecret, accessToken);
+    }
+    
+    private void testRegisterPublicClient (String accessToken)
+            throws ClientHandlerException, UniformInterfaceException,
+            KustvaktException {
+        OAuth2ClientJson json = new OAuth2ClientJson();
+        json.setName("LDAP test client");
+        json.setType(OAuth2ClientType.PUBLIC);
+        json.setDescription(
+                "Test registering a public client with LDAP authentication");
+
+        ClientResponse response = resource().path(API_VERSION).path("oauth2")
+                .path("client").path("register")
+                .header(Attributes.AUTHORIZATION, "Bearer " + accessToken)
+                .header(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON)
+                .entity(json).post(ClientResponse.class);
+
+        JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+
+        String clientId = node.at("/client_id").asText();
+        OAuth2Client client = clientDao.retrieveClientById(clientId);
+        assertEquals(testUserEmail, client.getRegisteredBy());
+    }
+    
+    private JsonNode testRegisterConfidentialClient (String accessToken)
+            throws ClientHandlerException, UniformInterfaceException,
+            KustvaktException {
+        OAuth2ClientJson json = new OAuth2ClientJson();
+        json.setName("LDAP test client");
+        json.setType(OAuth2ClientType.CONFIDENTIAL);
+        json.setRedirectURI(redirectUri);
+        json.setDescription(
+                "Test registering a confidential client with LDAP authentication");
+
+        ClientResponse response = resource().path(API_VERSION).path("oauth2")
+                .path("client").path("register")
+                .header(Attributes.AUTHORIZATION, "Bearer " + accessToken)
+                .header(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON)
+                .entity(json).post(ClientResponse.class);
+
+        JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+
+        String clientId = node.at("/client_id").asText();
+        OAuth2Client client = clientDao.retrieveClientById(clientId);
+        assertEquals(testUserEmail, client.getRegisteredBy());
+        return node;
+    }
+    
+    private void testRequestTokenWithAuthorization (String clientId,
+            String clientSecret, String accessToken) throws KustvaktException {
+        String authHeader = "Bearer " + accessToken;
+        ClientResponse response = resource().path(API_VERSION).path("oauth2")
+                .path("authorize")
+                .queryParam("response_type", "code")
+                .queryParam("client_id", clientId)
+                .queryParam("client_secret", clientSecret)
+                .header(Attributes.AUTHORIZATION, authHeader)
+                .get(ClientResponse.class);
+        
+        assertEquals(Status.TEMPORARY_REDIRECT.getStatusCode(),
+                response.getStatus());
+        URI redirectUri = response.getLocation();
+
+        MultiValueMap<String, String> params = UriComponentsBuilder
+                .fromUri(redirectUri).build().getQueryParams();
+        String code = params.getFirst("code");
+
+        response = requestTokenWithAuthorizationCodeAndForm(clientId, clientSecret, code);
+        JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
+
+        String at = node.at("/access_token").asText();
+        AccessToken accessTokenObj = accessDao.retrieveAccessToken(at);
+        assertEquals(testUserEmail, accessTokenObj.getUserId());
+
+        String refreshToken = node.at("/refresh_token").asText();
+        RefreshToken rt = refreshDao.retrieveRefreshToken(refreshToken);
+        assertEquals(testUserEmail, rt.getUserId());
+    }
+}
diff --git a/full/src/test/java/de/ids_mannheim/korap/authentication/LdapTest.java b/full/src/test/java/de/ids_mannheim/korap/authentication/LdapTest.java
deleted file mode 100644
index 8ddb5d8..0000000
--- a/full/src/test/java/de/ids_mannheim/korap/authentication/LdapTest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package de.ids_mannheim.korap.authentication;
-
-import static org.junit.Assert.assertEquals;
-
-import javax.ws.rs.core.Response.Status;
-
-import org.junit.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.sun.jersey.api.client.ClientResponse;
-
-import de.ids_mannheim.korap.config.FullConfiguration;
-import de.ids_mannheim.korap.constant.AuthenticationMethod;
-import de.ids_mannheim.korap.exceptions.KustvaktException;
-import de.ids_mannheim.korap.utils.JsonUtils;
-import de.ids_mannheim.korap.web.controller.OAuth2TestBase;
-
-public class LdapTest extends OAuth2TestBase {
-
-    @Autowired
-    private FullConfiguration config;
-    
-    @Test
-    public void testRequestTokenPasswordUnknownUser ()
-            throws KustvaktException {
-        
-        config.setOAuth2passwordAuthentication(AuthenticationMethod.LDAP);
-        ClientResponse response = requestTokenWithPassword(superClientId,
-                clientSecret, "unknown", "password");
-
-        assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
-
-        String entity = response.getEntity(String.class);
-        JsonNode node = JsonUtils.readTree(entity);
-        assertEquals(2022, node.at("/errors/0/0").asInt());
-        assertEquals(
-                "LDAP Authentication failed due to unknown user or password!",
-                node.at("/errors/0/1").asText());
-        config.setOAuth2passwordAuthentication(AuthenticationMethod.TEST);
-    }
-}