Added user info web-service (solved #566)

Change-Id: I2f0d2c4866698608c18ba665a5d6405e170a5d5f
diff --git a/core/Changes b/core/Changes
index 55f4ec9..cd92fca 100644
--- a/core/Changes
+++ b/core/Changes
@@ -1,6 +1,7 @@
 # version 0.69.4
 
 - Support token array in matchinfo (fixes #570; diewald)
+- Added user info web-service (solved #566)
 
 # version 0.69.3
 
diff --git a/core/src/main/java/de/ids_mannheim/korap/authentication/http/HttpAuthorizationHandler.java b/core/src/main/java/de/ids_mannheim/korap/authentication/http/HttpAuthorizationHandler.java
index 2470d4e..241e9ce 100644
--- a/core/src/main/java/de/ids_mannheim/korap/authentication/http/HttpAuthorizationHandler.java
+++ b/core/src/main/java/de/ids_mannheim/korap/authentication/http/HttpAuthorizationHandler.java
@@ -38,7 +38,7 @@
                     "Cannot parse authorization header value "
                             + authorizationHeader
                             + ". Use this format: [authentication "
-                            + "scheme] [Base64-encoded token]",
+                            + "scheme] [authentication token]",
                     authorizationHeader);
         }
 
diff --git a/core/src/main/java/de/ids_mannheim/korap/constant/OAuth2Scope.java b/core/src/main/java/de/ids_mannheim/korap/constant/OAuth2Scope.java
index b581faf..5055972 100644
--- a/core/src/main/java/de/ids_mannheim/korap/constant/OAuth2Scope.java
+++ b/core/src/main/java/de/ids_mannheim/korap/constant/OAuth2Scope.java
@@ -27,6 +27,8 @@
     SERIALIZE_QUERY,
     MATCH_INFO, 
     
+    USER_INFO,
+    
     USER_GROUP_INFO, 
     CREATE_USER_GROUP, 
     DELETE_USER_GROUP, 
diff --git a/full/Changes b/full/Changes
index 0652f7e..00c8159 100644
--- a/full/Changes
+++ b/full/Changes
@@ -2,6 +2,7 @@
 
 - Support token array in matchinfo (fixes #570; diewald)
 - Updated VC list API and deprecated owner VC list (addressed #580)
+- Added user info web-service (solved #566)
 
 # version 0.69.3
 
diff --git a/full/src/main/java/de/ids_mannheim/korap/service/UserService.java b/full/src/main/java/de/ids_mannheim/korap/service/UserService.java
new file mode 100644
index 0000000..de94d64
--- /dev/null
+++ b/full/src/main/java/de/ids_mannheim/korap/service/UserService.java
@@ -0,0 +1,16 @@
+package de.ids_mannheim.korap.service;
+
+import org.springframework.stereotype.Service;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+@Service
+public class UserService {
+
+    final static ObjectMapper mapper = new ObjectMapper();
+    
+    public JsonNode retrieveUserInfo (String username) {
+        return mapper.createObjectNode().put("username", username);
+    }
+}
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/UserController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/UserController.java
new file mode 100644
index 0000000..b0b6d6d
--- /dev/null
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/UserController.java
@@ -0,0 +1,52 @@
+package de.ids_mannheim.korap.web.controller;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.SecurityContext;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+import de.ids_mannheim.korap.constant.OAuth2Scope;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.oauth2.service.OAuth2ScopeService;
+import de.ids_mannheim.korap.security.context.TokenContext;
+import de.ids_mannheim.korap.service.UserService;
+import de.ids_mannheim.korap.web.KustvaktResponseHandler;
+import de.ids_mannheim.korap.web.filter.APIVersionFilter;
+import de.ids_mannheim.korap.web.filter.AuthenticationFilter;
+import de.ids_mannheim.korap.web.utils.ResourceFilters;
+
+@Controller
+@Path("{version}/user")
+@Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
+@ResourceFilters({ AuthenticationFilter.class, APIVersionFilter.class})
+public class UserController {
+
+    @Autowired
+    private KustvaktResponseHandler kustvaktResponseHandler;
+    @Autowired
+    private OAuth2ScopeService scopeService;
+    @Autowired
+    private UserService userService;
+
+    @GET
+    @Path("/info")
+    public JsonNode getUsername (
+        @Context SecurityContext securityContext) {
+            TokenContext context =
+                    (TokenContext) securityContext.getUserPrincipal();
+            try {
+                scopeService.verifyScope(context, OAuth2Scope.USER_INFO);
+                return userService.retrieveUserInfo(context.getUsername());
+            }
+            catch (KustvaktException e) {
+                throw kustvaktResponseHandler.throwit(e);
+            }
+        }
+}
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/UserControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/UserControllerTest.java
new file mode 100644
index 0000000..c8ad119
--- /dev/null
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/UserControllerTest.java
@@ -0,0 +1,99 @@
+package de.ids_mannheim.korap.web.controller;
+
+import static org.junit.Assert.assertEquals;
+
+import java.net.URI;
+
+import javax.ws.rs.ProcessingException;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.junit.Test;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
+import de.ids_mannheim.korap.config.Attributes;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.oauth2.constant.OAuth2ClientType;
+import de.ids_mannheim.korap.utils.JsonUtils;
+import de.ids_mannheim.korap.web.input.OAuth2ClientJson;
+
+public class UserControllerTest extends OAuth2TestBase {
+
+    private String username = "User\"ControllerTest";
+    private String userAuthHeader;
+
+    public UserControllerTest () throws KustvaktException {
+        userAuthHeader = HttpAuthorizationHandler
+                .createBasicAuthorizationHeaderValue(username, "password");
+    }
+
+    private OAuth2ClientJson createOAuth2Client () {
+        OAuth2ClientJson client = new OAuth2ClientJson();
+        client.setName("OWID client");
+        client.setType(OAuth2ClientType.PUBLIC);
+        client.setDescription("OWID web-based client");
+        client.setRedirectURI("https://www.owid.de");
+        return client;
+    }
+
+    private String registerClient ()
+            throws ProcessingException, KustvaktException {
+        OAuth2ClientJson clientJson = createOAuth2Client();
+        Response response = registerClient(username, clientJson);
+        JsonNode node = JsonUtils.readTree(response.readEntity(String.class));
+        String clientId = node.at("/client_id").asText();
+        return clientId;
+    }
+
+    private String requestOAuth2AccessToken (String clientId)
+            throws KustvaktException {
+        Response response = requestAuthorizationCode("code", clientId, "",
+                "user_info", "", userAuthHeader);
+
+        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, null, code);
+
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+
+        String entity = response.readEntity(String.class);
+        JsonNode node = JsonUtils.readTree(entity);
+
+        String accessToken = node.at("/access_token").asText();
+        return accessToken;
+    }
+
+    @Test
+    public void getUsername () throws ProcessingException, KustvaktException {
+        String clientId = registerClient();
+        String accessToken = requestOAuth2AccessToken(clientId);
+
+        Response response = target().path(API_VERSION).path("user").path("info")
+                .request()
+                .header(Attributes.AUTHORIZATION, "Bearer " + accessToken)
+                .get();
+        
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+        
+        String entity = response.readEntity(String.class);
+        JsonNode node = JsonUtils.readTree(entity);
+
+        assertEquals(username, node.at("/username").asText());
+
+        deregisterClient(username, clientId);
+    }
+    
+    
+    
+}