Added more parameter checks and OAuth2Client web-service tests.

Change-Id: I310ec386cc12c527d1b051e104e5ea95777189f4
diff --git a/full/Changes b/full/Changes
index 18e0aea..807c83e 100644
--- a/full/Changes
+++ b/full/Changes
@@ -3,6 +3,9 @@
 2022-03-03
  - Removed VCLoader.
  - Added foreign keys to the DB tables of access and refresh token scopes.
+2022-03-07
+ - Added more parameter checks and OAuth2Client web-service tests.
+
 
 # version 0.65.1
 
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ClientService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ClientService.java
index 64cafd6..51f8022 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ClientService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ClientService.java
@@ -83,6 +83,7 @@
             String registeredBy) throws KustvaktException {
         try {
             ParameterChecker.checkNameValue(clientJson.getName(), "client_name");
+            ParameterChecker.checkObjectValue(clientJson.getType(), "client_type");
         }
         catch (KustvaktException e) {
             throw new KustvaktException(e.getStatusCode(), e.getMessage(),
diff --git a/full/src/main/java/de/ids_mannheim/korap/service/QueryService.java b/full/src/main/java/de/ids_mannheim/korap/service/QueryService.java
index 3bda7f3..750dba4 100644
--- a/full/src/main/java/de/ids_mannheim/korap/service/QueryService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/service/QueryService.java
@@ -627,6 +627,8 @@
             String createdBy, QueryType queryType, String fieldName)
             throws KustvaktException {
         
+        ParameterChecker.checkStringValue(fieldName, "fieldName");
+        
         if (!adminDao.isAdmin(username)) {
             throw new KustvaktException(StatusCodes.AUTHORIZATION_FAILED,
                     "Unauthorized operation for user: " + username, username);
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ClientControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ClientControllerTest.java
index 05d683e..f688b31 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ClientControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ClientControllerTest.java
@@ -1,9 +1,9 @@
 package de.ids_mannheim.korap.web.controller;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.assertFalse;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -61,14 +61,30 @@
             }
         }
     }
-    
-    private ClientResponse registerClient (String username, 
+
+    private OAuth2ClientJson createOAuth2ClientJson (String name,
+            OAuth2ClientType type, String description) {
+        OAuth2ClientJson client = new OAuth2ClientJson();
+        if (name != null) {
+            client.setName(name);
+        }
+        client.setType(type);
+        if (description != null) {
+            client.setDescription(description);
+        }
+        return client;
+
+    }
+
+    private ClientResponse registerClient (String username,
             OAuth2ClientJson json) throws UniformInterfaceException,
             ClientHandlerException, KustvaktException {
         return resource().path(API_VERSION).path("oauth2").path("client")
                 .path("register")
-                .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
-                        .createBasicAuthorizationHeaderValue(username, "password"))
+                .header(Attributes.AUTHORIZATION,
+                        HttpAuthorizationHandler
+                                .createBasicAuthorizationHeaderValue(username,
+                                        "password"))
                 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
                 .header(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON)
                 .entity(json).post(ClientResponse.class);
@@ -116,20 +132,22 @@
         // confidential client
         clientInfo = retrieveClientInfo(confidentialClientId, "system");
         assertEquals(confidentialClientId, clientInfo.at("/id").asText());
-        assertEquals("non super confidential client", clientInfo.at("/name").asText());
+        assertEquals("non super confidential client",
+                clientInfo.at("/name").asText());
         assertNotNull(clientInfo.at("/url"));
-        assertEquals(false,clientInfo.at("/is_super").asBoolean());
+        assertEquals(false, clientInfo.at("/is_super").asBoolean());
         assertEquals("CONFIDENTIAL", clientInfo.at("/type").asText());
-        
+
         // super client
         clientInfo = retrieveClientInfo(superClientId, "system");
         assertEquals(superClientId, clientInfo.at("/id").asText());
-        assertEquals("super confidential client", clientInfo.at("/name").asText());
+        assertEquals("super confidential client",
+                clientInfo.at("/name").asText());
         assertNotNull(clientInfo.at("/url"));
         assertEquals("CONFIDENTIAL", clientInfo.at("/type").asText());
         assertTrue(clientInfo.at("/is_super").asBoolean());
     }
-    
+
     @Test
     public void testRegisterConfidentialClient () throws KustvaktException {
         ClientResponse response = registerConfidentialClient();
@@ -142,7 +160,7 @@
         assertNotNull(clientSecret);
 
         assertFalse(clientId.contains("a"));
-            
+
         testResetConfidentialClientSecret(clientId, clientSecret);
         testDeregisterConfidentialClient(clientId);
     }
@@ -151,49 +169,91 @@
     public void testRegisterClientNameTooShort ()
             throws UniformInterfaceException, ClientHandlerException,
             KustvaktException {
-        OAuth2ClientJson json = new OAuth2ClientJson();
-        json.setName("R");
-        json.setType(OAuth2ClientType.PUBLIC);
+        OAuth2ClientJson clientJson =
+                createOAuth2ClientJson("R", OAuth2ClientType.PUBLIC, null);
 
-        ClientResponse response = registerClient(username, json);
+        ClientResponse response = registerClient(username, clientJson);
         String entity = response.getEntity(String.class);
         JsonNode node = JsonUtils.readTree(entity);
         assertEquals("client_name must contain at least 3 characters",
                 node.at("/error_description").asText());
-        assertEquals("invalid_request",
-                node.at("/error").asText());
+        assertEquals("invalid_request", node.at("/error").asText());
         assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
     }
-    
+
+    @Test
+    public void testRegisterClientEmptyName () throws UniformInterfaceException,
+            ClientHandlerException, KustvaktException {
+        OAuth2ClientJson clientJson =
+                createOAuth2ClientJson("", OAuth2ClientType.PUBLIC, null);
+
+        ClientResponse response = registerClient(username, clientJson);
+        String entity = response.getEntity(String.class);
+        JsonNode node = JsonUtils.readTree(entity);
+        assertEquals("client_name must contain at least 3 characters",
+                node.at("/error_description").asText());
+        assertEquals("invalid_request", node.at("/error").asText());
+        assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
+    }
+
+    @Test
+    public void testRegisterClientMissingName ()
+            throws UniformInterfaceException, ClientHandlerException,
+            KustvaktException {
+        OAuth2ClientJson clientJson =
+                createOAuth2ClientJson(null, OAuth2ClientType.PUBLIC, null);
+
+        ClientResponse response = registerClient(username, clientJson);
+        String entity = response.getEntity(String.class);
+        JsonNode node = JsonUtils.readTree(entity);
+        assertEquals("client_name is null",
+                node.at("/error_description").asText());
+        assertEquals("invalid_request", node.at("/error").asText());
+        assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
+    }
+
     @Test
     public void testRegisterClientMissingDescription ()
             throws UniformInterfaceException, ClientHandlerException,
             KustvaktException {
-        OAuth2ClientJson json = new OAuth2ClientJson();
-        json.setName("R client");
-        json.setType(OAuth2ClientType.PUBLIC);
+        OAuth2ClientJson clientJson = createOAuth2ClientJson("R client",
+                OAuth2ClientType.PUBLIC, null);
 
-        ClientResponse response = registerClient(username, json);
+        ClientResponse response = registerClient(username, clientJson);
         String entity = response.getEntity(String.class);
         JsonNode node = JsonUtils.readTree(entity);
         assertEquals("client_description is null",
                 node.at("/error_description").asText());
-        assertEquals("invalid_request",
-                node.at("/error").asText());
+        assertEquals("invalid_request", node.at("/error").asText());
         assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
     }
-    
+
+    @Test
+    public void testRegisterClientMissingType ()
+            throws UniformInterfaceException, ClientHandlerException,
+            KustvaktException {
+        OAuth2ClientJson clientJson =
+                createOAuth2ClientJson("R client", null, null);
+
+        ClientResponse response = registerClient(username, clientJson);
+        String entity = response.getEntity(String.class);
+        JsonNode node = JsonUtils.readTree(entity);
+        assertEquals("client_type is null",
+                node.at("/error_description").asText());
+        assertEquals("invalid_request", node.at("/error").asText());
+        assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
+    }
+
     @Test
     public void testRegisterPublicClient () throws UniformInterfaceException,
             ClientHandlerException, KustvaktException {
-        OAuth2ClientJson json = new OAuth2ClientJson();
-        json.setName("OAuth2PublicClient");
-        json.setType(OAuth2ClientType.PUBLIC);
-        json.setUrl("http://test.public.client.com");
-        json.setRedirectURI("https://test.public.client.com/redirect");
-        json.setDescription("This is a public test client.");
+        OAuth2ClientJson clientJson =
+                createOAuth2ClientJson("OAuth2PublicClient",
+                        OAuth2ClientType.PUBLIC, "A public test client.");
+        clientJson.setUrl("http://test.public.client.com");
+        clientJson.setRedirectURI("https://test.public.client.com/redirect");
 
-        ClientResponse response = registerClient(username, json);
+        ClientResponse response = registerClient(username, clientJson);
 
         String entity = response.getEntity(String.class);
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
@@ -202,10 +262,45 @@
         assertNotNull(clientId);
         assertTrue(node.at("/client_secret").isMissingNode());
 
+        testRegisterClientUnauthorizedScope(clientId);
         testResetPublicClientSecret(clientId);
-        testAccessTokenAfterDeregistration(clientId, null,null);
+        testAccessTokenAfterDeregistration(clientId, null, null);
     }
-    
+
+    private void testRegisterClientUnauthorizedScope (String clientId)
+            throws UniformInterfaceException, ClientHandlerException,
+            KustvaktException {
+
+        String userAuthHeader = HttpAuthorizationHandler
+                .createBasicAuthorizationHeaderValue("dory", "password");
+        String code = requestAuthorizationCode(clientId, "", null,
+                userAuthHeader, null);
+        ClientResponse response = requestTokenWithAuthorizationCodeAndForm(
+                clientId, clientSecret, code, null);
+        JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
+
+        assertEquals("match_info search", node.at("/scope").asText());
+
+        String accessToken = node.at("/access_token").asText();
+
+        OAuth2ClientJson clientJson = createOAuth2ClientJson("R client",
+                OAuth2ClientType.PUBLIC, null);
+
+        response = resource().path(API_VERSION).path("oauth2").path("client")
+                .path("register")
+                .header(Attributes.AUTHORIZATION, "Bearer " + accessToken)
+                .header(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON)
+                .entity(clientJson).post(ClientResponse.class);
+
+        String entity = response.getEntity(String.class);
+        node = JsonUtils.readTree(entity);
+        assertEquals(StatusCodes.AUTHORIZATION_FAILED,
+                node.at("/errors/0/0").asInt());
+        assertEquals("Scope register_client is not authorized",
+                node.at("/errors/0/1").asText());
+        assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
+    }
+
     @Test
     public void testRegisterClientUsingPlainJson ()
             throws UniformInterfaceException, ClientHandlerException,
@@ -234,16 +329,15 @@
         testResetPublicClientSecret(clientId);
         testAccessTokenAfterDeregistration(clientId, null, null);
     }
-    
+
     @Test
     public void testRegisterDesktopApp () throws UniformInterfaceException,
             ClientHandlerException, KustvaktException {
-        OAuth2ClientJson json = new OAuth2ClientJson();
-        json.setName("OAuth2DesktopClient");
-        json.setType(OAuth2ClientType.PUBLIC);
-        json.setDescription("This is a desktop test client.");
+        OAuth2ClientJson clientJson = createOAuth2ClientJson(
+                "OAuth2DesktopClient", OAuth2ClientType.PUBLIC,
+                "This is a desktop test client.");
 
-        ClientResponse response = registerClient(username, json);
+        ClientResponse response = registerClient(username, clientJson);
 
         String entity = response.getEntity(String.class);
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
@@ -254,20 +348,20 @@
 
         testDeregisterPublicClientMissingUserAuthentication(clientId);
         testDeregisterPublicClientMissingId();
-        testDeregisterPublicClient(clientId,username);
+        testDeregisterPublicClient(clientId, username);
     }
 
     @Test
-    public void testRegisterMultipleDesktopApps () throws UniformInterfaceException,
-            ClientHandlerException, KustvaktException {
+    public void testRegisterMultipleDesktopApps ()
+            throws UniformInterfaceException, ClientHandlerException,
+            KustvaktException {
 
         // First client
-        OAuth2ClientJson json = new OAuth2ClientJson();
-        json.setName("OAuth2DesktopClient1");
-        json.setType(OAuth2ClientType.PUBLIC);
-        json.setDescription("This is a desktop test client.");
+        OAuth2ClientJson clientJson =
+                createOAuth2ClientJson("OAuth2DesktopClient1",
+                        OAuth2ClientType.PUBLIC, "A desktop test client.");
 
-        ClientResponse response = registerClient(username, json);
+        ClientResponse response = registerClient(username, clientJson);
 
         String entity = response.getEntity(String.class);
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
@@ -277,12 +371,10 @@
         assertTrue(node.at("/client_secret").isMissingNode());
 
         // Second client
-        json = new OAuth2ClientJson();
-        json.setName("OAuth2DesktopClient2");
-        json.setType(OAuth2ClientType.PUBLIC);
-        json.setDescription("This is another desktop test client.");
+        clientJson = createOAuth2ClientJson("OAuth2DesktopClient2",
+                OAuth2ClientType.PUBLIC, "Another desktop test client.");
 
-        response = registerClient(username, json);
+        response = registerClient(username, clientJson);
 
         entity = response.getEntity(String.class);
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
@@ -298,7 +390,7 @@
         testAccessTokenAfterDeregistration(clientId2, null,
                 "https://OAuth2DesktopClient2.com");
     }
-    
+
     private void testAccessTokenAfterDeregistration (String clientId,
             String clientSecret, String redirectUri) throws KustvaktException {
         String userAuthHeader = HttpAuthorizationHandler
@@ -360,7 +452,8 @@
                         .createBasicAuthorizationHeaderValue(username, "pass"))
                 .delete(ClientResponse.class);
 
-        assertEquals(Status.METHOD_NOT_ALLOWED.getStatusCode(), response.getStatus());
+        assertEquals(Status.METHOD_NOT_ALLOWED.getStatusCode(),
+                response.getStatus());
     }
 
     private void testDeregisterPublicClient (String clientId, String username)
@@ -530,14 +623,15 @@
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
 
         String entity = response.getEntity(String.class);
-//        System.out.println(entity);
+        // System.out.println(entity);
         JsonNode node = JsonUtils.readTree(entity);
         assertEquals(2, node.size());
         assertEquals(confidentialClientId, node.at("/0/client_id").asText());
         assertEquals(publicClientId, node.at("/1/client_id").asText());
-        
-        assertEquals("non super confidential client",node.at("/0/client_name").asText());
-        assertEquals("CONFIDENTIAL",node.at("/0/client_type").asText());
+
+        assertEquals("non super confidential client",
+                node.at("/0/client_name").asText());
+        assertEquals("CONFIDENTIAL", node.at("/0/client_type").asText());
         assertFalse(node.at("/0/client_url").isMissingNode());
         assertFalse(node.at("/0/client_description").isMissingNode());
     }
@@ -555,8 +649,8 @@
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
 
         // client 1
-        String code = requestAuthorizationCode(publicClientId, "",
-                null, userAuthHeader);
+        String code = requestAuthorizationCode(publicClientId, "", null,
+                userAuthHeader);
         response = requestTokenWithAuthorizationCodeAndForm(publicClientId, "",
                 code);
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
@@ -576,62 +670,62 @@
         testListAuthorizedClientWithMultipleRefreshTokens(userAuthHeader);
         testListAuthorizedClientWithMultipleAccessTokens(userAuthHeader);
         testListWithClientsFromAnotherUser(userAuthHeader);
-        
+
         // revoke client 1
         testRevokeAllTokenViaSuperClient(publicClientId, userAuthHeader,
                 accessToken);
-        
+
         // revoke client 2
         node = JsonUtils.readTree(response.getEntity(String.class));
         accessToken = node.at("/access_token").asText();
         refreshToken = node.at("/refresh_token").asText();
         testRevokeAllTokenViaSuperClient(confidentialClientId, userAuthHeader,
                 accessToken);
-        testRequestTokenWithRevokedRefreshToken(confidentialClientId, clientSecret,
-                refreshToken);
+        testRequestTokenWithRevokedRefreshToken(confidentialClientId,
+                clientSecret, refreshToken);
     }
 
     private void testListAuthorizedClientWithMultipleRefreshTokens (
             String userAuthHeader) throws KustvaktException {
         // client 2
-        String code = requestAuthorizationCode(confidentialClientId, clientSecret,
-                null, userAuthHeader);
+        String code = requestAuthorizationCode(confidentialClientId,
+                clientSecret, null, userAuthHeader);
         ClientResponse response = requestTokenWithAuthorizationCodeAndForm(
                 confidentialClientId, clientSecret, code);
 
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
-        
+
         requestAuthorizedClientList(userAuthHeader);
     }
-    
+
     private void testListAuthorizedClientWithMultipleAccessTokens (
             String userAuthHeader) throws KustvaktException {
         // client 1
-        String code = requestAuthorizationCode(publicClientId, "",
-                null, userAuthHeader);
+        String code = requestAuthorizationCode(publicClientId, "", null,
+                userAuthHeader);
         ClientResponse response = requestTokenWithAuthorizationCodeAndForm(
                 publicClientId, "", code);
 
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
-        
+
         requestAuthorizedClientList(userAuthHeader);
     }
-    
-    private void testListWithClientsFromAnotherUser (
-            String userAuthHeader) throws KustvaktException {
+
+    private void testListWithClientsFromAnotherUser (String userAuthHeader)
+            throws KustvaktException {
 
         String aaaAuthHeader = HttpAuthorizationHandler
                 .createBasicAuthorizationHeaderValue("aaa", "pwd");
-        
+
         // client 1
-        String code = requestAuthorizationCode(publicClientId, "",
-                null, aaaAuthHeader);
+        String code = requestAuthorizationCode(publicClientId, "", null,
+                aaaAuthHeader);
         ClientResponse response = requestTokenWithAuthorizationCodeAndForm(
                 publicClientId, "", code);
-        
+
         JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
         String accessToken1 = node.at("/access_token").asText();
-        
+
         // client 2
         code = requestAuthorizationCode(confidentialClientId, clientSecret,
                 null, aaaAuthHeader);
@@ -649,8 +743,8 @@
                 accessToken1);
         testRevokeAllTokenViaSuperClient(confidentialClientId, aaaAuthHeader,
                 accessToken2);
-        testRequestTokenWithRevokedRefreshToken(confidentialClientId, clientSecret,
-                refreshToken);
+        testRequestTokenWithRevokedRefreshToken(confidentialClientId,
+                clientSecret, refreshToken);
     }
 
     private void testRevokeAllTokenViaSuperClient (String clientId,
@@ -683,19 +777,16 @@
         assertEquals("Access token is invalid",
                 node.at("/errors/0/1").asText());
     }
-    
+
     @Test
-    public void testListRegisteredClients ()
-            throws KustvaktException {
-        
+    public void testListRegisteredClients () throws KustvaktException {
+
         String clientName = "OAuth2DoryClient";
-        OAuth2ClientJson json = new OAuth2ClientJson();
-        json.setName(clientName);
-        json.setType(OAuth2ClientType.PUBLIC);
-        json.setDescription("This is dory client.");
+        OAuth2ClientJson json = createOAuth2ClientJson(clientName,
+                OAuth2ClientType.PUBLIC, "Dory's client.");
 
         registerClient("dory", json);
-        
+
         MultivaluedMap<String, String> form = new MultivaluedMapImpl();
         form.add("super_client_id", superClientId);
         form.add("super_client_secret", clientSecret);
@@ -711,10 +802,11 @@
 
         String entity = response.getEntity(String.class);
         JsonNode node = JsonUtils.readTree(entity);
-        
+
         assertEquals(1, node.size());
         assertEquals(clientName, node.at("/0/client_name").asText());
-        assertEquals(OAuth2ClientType.PUBLIC.name(), node.at("/0/client_type").asText());
+        assertEquals(OAuth2ClientType.PUBLIC.name(),
+                node.at("/0/client_type").asText());
         String clientId = node.at("/0/client_id").asText();
         testDeregisterPublicClient(clientId, "dory");
     }