Implemented OAuth2 client info controller, super clients and unlimited
authorization scopes. Enabled using Bearer tokens as user authentication
methods for many controllers including OAuth2 controllers.

Change-Id: I1043164acbe49501210a6fca7f4531d110eb81a5
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2AccessTokenTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2AccessTokenTest.java
index 98f3434..78d91aa 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2AccessTokenTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2AccessTokenTest.java
@@ -2,22 +2,27 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
+import java.net.URI;
 
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response.Status;
 
 import org.apache.http.entity.ContentType;
 import org.apache.oltu.oauth2.common.message.types.GrantType;
+import org.apache.oltu.oauth2.common.message.types.TokenType;
 import org.junit.Test;
+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.ClientResponse;
 import com.sun.jersey.core.util.MultivaluedMapImpl;
 
-import de.ids_mannheim.korap.authentication.http.TransferEncoding;
+import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
 import de.ids_mannheim.korap.config.Attributes;
 import de.ids_mannheim.korap.config.SpringJerseyTest;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
@@ -27,15 +32,48 @@
 
 public class OAuth2AccessTokenTest extends SpringJerseyTest {
 
-    private String clientId = "fCBbQkAyYzI4NzUxMg";
+    // normal client
+    private String clientId = "9aHsGW6QflV13ixNpez";
+    private String superClientId = "fCBbQkAyYzI4NzUxMg";
+    private String clientSecret = "secret";
 
-    private JsonNode requestToken () throws KustvaktException {
+    private String requestAuthorizationCode (String scope, String authHeader)
+            throws KustvaktException {
         MultivaluedMap<String, String> form = new MultivaluedMapImpl();
-        form.add("grant_type", "password");
+        form.add("response_type", "code");
         form.add("client_id", clientId);
-        form.add("client_secret", "secret");
-        form.add("username", "dory");
-        form.add("password", "password");
+        form.add("client_secret", clientSecret);
+        if (scope != null) {
+            form.add("scope", scope);
+        }
+
+        ClientResponse response = resource().path("oauth2").path("authorize")
+                .header(Attributes.AUTHORIZATION, authHeader)
+                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+                .header(HttpHeaders.CONTENT_TYPE,
+                        ContentType.APPLICATION_FORM_URLENCODED)
+                .entity(form).post(ClientResponse.class);
+
+        assertEquals(Status.TEMPORARY_REDIRECT.getStatusCode(),
+                response.getStatus());
+        URI redirectUri = response.getLocation();
+        MultiValueMap<String, String> params = UriComponentsBuilder
+                .fromUri(redirectUri).build().getQueryParams();
+        return params.getFirst("code");
+    }
+
+    // client credentials as form params
+    private JsonNode requestTokenWithAuthorizationCodeGrant ()
+            throws KustvaktException {
+        String authHeader = HttpAuthorizationHandler
+                .createBasicAuthorizationHeaderValue("dory", "password");
+        String code = requestAuthorizationCode(null, authHeader);
+
+        MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+        form.add("grant_type", "authorization_code");
+        form.add("client_id", clientId);
+        form.add("client_secret", clientSecret);
+        form.add("code", code);
 
         ClientResponse response = resource().path("oauth2").path("token")
                 .header(HttpHeaders.CONTENT_TYPE,
@@ -43,45 +81,85 @@
                 .entity(form).post(ClientResponse.class);
 
         String entity = response.getEntity(String.class);
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
         JsonNode node = JsonUtils.readTree(entity);
         return node;
     }
 
-    @Test
-    public void testListVCScope () throws KustvaktException {
+    // client credentials in authorization header
+    private JsonNode requestTokenWithAuthorizationHeader (String code)
+            throws KustvaktException {
         MultivaluedMap<String, String> form = new MultivaluedMapImpl();
-        form.add("grant_type", "password");
-        form.add("client_id", "fCBbQkAyYzI4NzUxMg");
-        form.add("client_secret", "secret");
-        form.add("username", "dory");
-        form.add("password", "password");
-        form.add("scope", OAuth2Scope.VC_INFO.toString());
+        form.add("grant_type", "authorization_code");
+        form.add("client_id", clientId);
+        form.add("code", code);
 
         ClientResponse response = resource().path("oauth2").path("token")
-                .header(HttpHeaders.AUTHORIZATION,
-                        "Bearer" + TransferEncoding
-                                .encodeBase64("fCBbQkAyYzI4NzUxMg", "secret"))
+                .header(Attributes.AUTHORIZATION,
+                        HttpAuthorizationHandler
+                                .createBasicAuthorizationHeaderValue(clientId,
+                                        clientSecret))
                 .header(HttpHeaders.CONTENT_TYPE,
                         ContentType.APPLICATION_FORM_URLENCODED)
                 .entity(form).post(ClientResponse.class);
 
         String entity = response.getEntity(String.class);
-        JsonNode node = JsonUtils.readTree(entity);
-        String token = node.at("/access_token").asText();
+        return JsonUtils.readTree(entity);
+    }
 
-        response = resource().path("vc").path("list")
+    @Test
+    public void testScopeWithSuperClient () throws KustvaktException {
+        MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+        form.add("grant_type", "password");
+        form.add("client_id", superClientId);
+        form.add("client_secret", clientSecret);
+        form.add("username", "dory");
+        form.add("password", "password");
+
+        ClientResponse response = resource().path("oauth2").path("token")
+                .header(HttpHeaders.CONTENT_TYPE,
+                        ContentType.APPLICATION_FORM_URLENCODED)
+                .entity(form).post(ClientResponse.class);
+
+        JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
+        assertEquals("all", node.at("/scope").asText());
+        String accessToken = node.at("/access_token").asText();
+
+        // test list user group
+        response = resource().path("group").path("list")
+                .header(Attributes.AUTHORIZATION, "Bearer " + accessToken)
+                .get(ClientResponse.class);
+
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+        node = JsonUtils.readTree(response.getEntity(String.class));
+        assertEquals(2, node.size());
+    }
+
+    @Test
+    public void testCustomAuthorizationScope () throws KustvaktException {
+        String authHeader = HttpAuthorizationHandler
+                .createBasicAuthorizationHeaderValue("dory", "password");
+        String code = requestAuthorizationCode(OAuth2Scope.VC_INFO.toString(),
+                authHeader);
+        JsonNode node = requestTokenWithAuthorizationHeader(code);
+
+        String token = node.at("/access_token").asText();
+        assertTrue(node.at("/scope").asText()
+                .contains(OAuth2Scope.VC_INFO.toString()));
+
+        ClientResponse response = resource().path("vc").path("list")
                 .header(Attributes.AUTHORIZATION, "Bearer " + token)
                 .get(ClientResponse.class);
 
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
-        entity = response.getEntity(String.class);
-        node = JsonUtils.readTree(entity);
+        node = JsonUtils.readTree(response.getEntity(String.class));
         assertEquals(4, node.size());
     }
 
     @Test
-    public void testTokenAccessScope () throws KustvaktException, IOException {
-        String accessToken = requestToken().at("/access_token").asText();
+    public void testDefaultScope () throws KustvaktException, IOException {
+        String accessToken = requestTokenWithAuthorizationCodeGrant()
+                .at("/access_token").asText();
         testListVCScopeNotAuthorized(accessToken);
         testListVCAccessBearerNotAuthorize(accessToken);
         testSearchWithOAuth2Token(accessToken);
@@ -116,7 +194,7 @@
         JsonNode node = JsonUtils.readTree(entity);
         assertEquals(StatusCodes.AUTHORIZATION_FAILED,
                 node.at("/errors/0/0").asInt());
-        assertEquals("Token type Bearer is not allowed",
+        assertEquals("Scope vc_access_info is not authorized",
                 node.at("/errors/0/1").asText());
     }
 
@@ -161,10 +239,11 @@
     @Test
     public void testRevokeAccessTokenConfidentialClient ()
             throws KustvaktException {
-        String accessToken = requestToken().at("/access_token").asText();
+        String accessToken = requestTokenWithAuthorizationCodeGrant()
+                .at("/access_token").asText();
         MultivaluedMap<String, String> form = new MultivaluedMapImpl();
         form.add("token", accessToken);
-        form.add("client_id", "fCBbQkAyYzI4NzUxMg");
+        form.add("client_id", clientId);
         form.add("client_secret", "secret");
 
         ClientResponse response = resource().path("oauth2").path("revoke")
@@ -200,10 +279,10 @@
     @Test
     public void testRevocationAfterRequestRefreshToken ()
             throws KustvaktException {
-        JsonNode node = requestToken();
+        JsonNode node = requestTokenWithAuthorizationCodeGrant();
         String accessToken = node.at("/access_token").asText();
         String refreshToken = node.at("/refresh_token").asText();
-        
+
         MultivaluedMap<String, String> form = new MultivaluedMapImpl();
         form.add("grant_type", GrantType.REFRESH_TOKEN.toString());
         form.add("client_id", clientId);
@@ -221,8 +300,65 @@
 
         node = JsonUtils.readTree(entity);
         assertNotNull(node.at("/access_token").asText());
-        assertEquals(refreshToken,node.at("/refresh_token").asText());
-        
+        assertEquals(refreshToken, node.at("/refresh_token").asText());
+
         testSearchWithRevokedToken(accessToken);
     }
+
+    @Test
+    public void testRequestAuthorizationWithBearerTokenUnauthorized () throws KustvaktException {
+        String userAuthToken = requestTokenWithAuthorizationCodeGrant()
+                .at("/access_token").asText();
+
+        MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+        form.add("response_type", "code");
+        form.add("client_id", clientId);
+        form.add("client_secret", clientSecret);
+
+        ClientResponse response = resource().path("oauth2").path("authorize")
+                .header(Attributes.AUTHORIZATION, "Bearer " + userAuthToken)
+                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+                .header(HttpHeaders.CONTENT_TYPE,
+                        ContentType.APPLICATION_FORM_URLENCODED)
+                .entity(form).post(ClientResponse.class);
+
+        assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
+        
+        JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
+        assertEquals(StatusCodes.AUTHORIZATION_FAILED,
+                node.at("/errors/0/0").asInt());
+        assertEquals("Scope authorize is not authorized",
+                node.at("/errors/0/1").asText());
+    }
+
+    @Test
+    public void testRequestAuthorizationWithBearerToken ()
+            throws KustvaktException {
+        String userAuthToken = requestTokenWithPasswordGrant();
+        String code = requestAuthorizationCode(null, "Bearer " + userAuthToken);
+        assertNotNull(code);
+    }
+
+    private String requestTokenWithPasswordGrant () throws KustvaktException {
+        MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+        form.add("grant_type", "password");
+        form.add("client_id", superClientId);
+        form.add("client_secret", clientSecret);
+        form.add("username", "dory");
+        form.add("password", "password");
+
+        ClientResponse response = resource().path("oauth2").path("token")
+                .header(HttpHeaders.CONTENT_TYPE,
+                        ContentType.APPLICATION_FORM_URLENCODED)
+                .entity(form).post(ClientResponse.class);
+        String entity = response.getEntity(String.class);
+
+        JsonNode node = JsonUtils.readTree(entity);
+        String token = node.at("/access_token").asText();
+        assertNotNull(token);
+        assertEquals(TokenType.BEARER.toString(),
+                node.at("/token_type").asText());
+        assertNotNull(node.at("/expires_in").asText());
+        return token;
+    }
 }
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 ffecbb3..9c3d536 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
@@ -94,7 +94,6 @@
         testDeregisterConfidentialClient(clientId, newclientSecret);
     }
 
-
     private void testRegisterClientNonUniqueURL () throws KustvaktException {
         ClientResponse response = registerConfidentialClient();
         assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
@@ -127,9 +126,8 @@
         assertNotNull(clientId);
         assertTrue(node.at("/client_secret").isMissingNode());
 
-        testDeregisterPublicClientMissingUserAuthentication(clientId);
-        testDeregisterPublicClientMissingId();
-        testDeregisterPublicClient(clientId);
+        testResetPublicClientSecret(clientId);
+        testAccessTokenAfterDeregistration(clientId);
     }
 
     @Test
@@ -155,35 +153,9 @@
         assertNotNull(clientId);
         assertTrue(node.at("/client_secret").isMissingNode());
 
-        testResetPublicClientSecret(clientId);
-    }
-
-    @Test
-    public void testRegisterNativeClient () throws UniformInterfaceException,
-            ClientHandlerException, KustvaktException {
-        OAuth2ClientJson json = new OAuth2ClientJson();
-        json.setName("NativeClient");
-        json.setType(OAuth2ClientType.PUBLIC);
-        json.setUrl("http://korap.ids-mannheim.de/native");
-        json.setRedirectURI("https://korap.ids-mannheim.de/native/redirect");
-        json.setDescription("This is a native test client.");
-
-        ClientResponse response = resource().path("oauth2").path("client")
-                .path("register")
-                .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
-                        .createBasicAuthorizationHeaderValue(username, "pass"))
-                .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
-                .header(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON)
-                .entity(json).post(ClientResponse.class);
-
-        String entity = response.getEntity(String.class);
-        assertEquals(Status.OK.getStatusCode(), response.getStatus());
-        JsonNode node = JsonUtils.readTree(entity);
-        String clientId = node.at("/client_id").asText();
-
-        // EM: need to check native
-
-        testAccessTokenAfterDeregistration(clientId);
+        testDeregisterPublicClientMissingUserAuthentication(clientId);
+        testDeregisterPublicClientMissingId();
+        testDeregisterPublicClient(clientId);
     }
 
     private void testAccessTokenAfterDeregistration (String clientId)
@@ -420,4 +392,55 @@
 
         return newClientSecret;
     }
+
+    @Test
+    public void testUpdateClientPrivilege () throws KustvaktException {
+        ClientResponse response = registerConfidentialClient();
+        JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
+        String clientId = node.at("/client_id").asText();
+
+        MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+        form.add("client_id", clientId);
+        form.add("super", "true");
+
+        updateClientPrivilege(form);
+        node = retrieveClientInfo(clientId, "admin");
+        assertTrue(node.at("/isSuper").asBoolean());
+
+        form.remove("super");
+        form.add("super", "false");
+        updateClientPrivilege(form);
+        node = retrieveClientInfo(clientId, username);
+        assertTrue(node.at("/isSuper").isMissingNode());
+
+    }
+
+    private void updateClientPrivilege (MultivaluedMap<String, String> form)
+            throws UniformInterfaceException, ClientHandlerException,
+            KustvaktException {
+        ClientResponse response = resource().path("oauth2").path("client")
+                .path("privilege")
+                .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
+                        .createBasicAuthorizationHeaderValue("admin", "pass"))
+                .header(HttpHeaders.CONTENT_TYPE,
+                        ContentType.APPLICATION_FORM_URLENCODED)
+                .entity(form).post(ClientResponse.class);
+
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+    }
+
+    private JsonNode retrieveClientInfo (String clientId, String username)
+            throws UniformInterfaceException, ClientHandlerException,
+            KustvaktException {
+        ClientResponse response = resource().path("oauth2").path("client")
+                .path("info").path(clientId)
+                .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
+                        .createBasicAuthorizationHeaderValue(username, "pass"))
+                .get(ClientResponse.class);
+
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+
+        String entity = response.getEntity(String.class);
+        return JsonUtils.readTree(entity);
+    }
 }
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ControllerTest.java
index 3dabb7b..5d452e8 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ControllerTest.java
@@ -181,6 +181,46 @@
     }
 
     @Test
+    public void testRequestTokenAuthorizationPublic () throws KustvaktException {
+        String clientId = "8bIDtZnH6NvRkW2Fq";
+        MultivaluedMap<String, String> authForm = new MultivaluedMapImpl();
+        authForm.add("response_type", "code");
+        authForm.add("client_id", clientId);
+
+        ClientResponse response = requestAuthorization(authForm);
+        URI redirectUri = response.getLocation();
+        MultiValueMap<String, String> params = UriComponentsBuilder
+                .fromUri(redirectUri).build().getQueryParams();
+        String code = params.get("code").get(0);
+        
+        MultivaluedMap<String, String> tokenForm = new MultivaluedMapImpl();
+        tokenForm.add("grant_type", "authorization_code");
+        tokenForm.add("client_id", clientId);
+        tokenForm.add("code", code);
+
+        response = requestToken(tokenForm);
+        String entity = response.getEntity(String.class);
+        JsonNode node = JsonUtils.readTree(entity);
+        
+        String accessToken = node.at("/access_token").asText();
+        String refreshToken = node.at("/refresh_token").asText();
+        
+        assertEquals(TokenType.BEARER.toString(),
+                node.at("/token_type").asText());
+        assertNotNull(node.at("/expires_in").asText());
+        
+        testRevokeTokenPublicClient(accessToken, clientId, "access_token");
+        
+        testRequestRefreshTokenInvalidScope(clientId, refreshToken);
+        testRequestRefreshTokenPublicClient(clientId, refreshToken);
+        testRequestRefreshTokenInvalidClient(refreshToken);
+        testRequestRefreshTokenInvalidRefreshToken(clientId);
+        
+        testRevokeTokenPublicClient(refreshToken, clientId, "refresh_token");
+        testRequestRefreshWithRevokedRefreshToken(clientId, refreshToken);
+    }
+    
+    @Test
     public void testRequestTokenAuthorizationConfidential ()
             throws KustvaktException {
 
@@ -203,7 +243,6 @@
         tokenForm.add("client_id", "fCBbQkAyYzI4NzUxMg");
         tokenForm.add("client_secret", "secret");
         tokenForm.add("code", code);
-        System.out.println(code);
 
         response = requestToken(tokenForm);
         String entity = response.getEntity(String.class);
@@ -437,7 +476,7 @@
     @Test
     public void testRequestTokenPasswordGrantPublic ()
             throws KustvaktException {
-        String clientId = "iBr3LsTCxOj7D2o0A5m";
+        String clientId = "8bIDtZnH6NvRkW2Fq";
         MultivaluedMap<String, String> form = new MultivaluedMapImpl();
         form.add("grant_type", "password");
         form.add("username", "dory");
@@ -447,35 +486,23 @@
         ClientResponse response = requestToken(form);
         String entity = response.getEntity(String.class);
 
-        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+        assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
 
         JsonNode node = JsonUtils.readTree(entity);
-        String accessToken = node.at("/access_token").asText();
-        assertEquals(TokenType.BEARER.toString(),
-                node.at("/token_type").asText());
-        assertNotNull(node.at("/expires_in").asText());
-
-
-        testRevokeTokenPublicClient(accessToken, clientId, "access_token");
-
-        String refreshToken = node.at("/refresh_token").asText();
-        testRequestRefreshTokenInvalidScope(clientId, refreshToken);
-        testRequestRefreshTokenPublicClient(clientId, refreshToken);
-        testRequestRefreshTokenInvalidClient(refreshToken);
-        testRequestRefreshTokenInvalidRefreshToken(clientId);
-        
-        testRevokeTokenPublicClient(refreshToken, clientId, "refresh_token");
-        testRequestRefreshWithRevokedRefreshToken(clientId, refreshToken);
+        assertEquals(OAuth2Error.UNAUTHORIZED_CLIENT,
+                node.at("/error").asText());
+        assertEquals("Password grant is not allowed for third party clients",
+                node.at("/error_description").asText());
     }
 
     @Test
-    public void testRequestTokenPasswordGrantNonNative ()
+    public void testRequestTokenPasswordGrantConfidentialNonSuper ()
             throws KustvaktException {
         MultivaluedMap<String, String> form = new MultivaluedMapImpl();
         form.add("grant_type", "password");
         form.add("username", "dory");
         form.add("password", "password");
-        // confidential nonnative
+        // confidential non-super
         form.add("client_id", "9aHsGW6QflV13ixNpez");
         form.add("client_secret", "secret");
 
@@ -639,7 +666,7 @@
             throws KustvaktException {
         MultivaluedMap<String, String> form = new MultivaluedMapImpl();
         form.add("grant_type", GrantType.REFRESH_TOKEN.toString());
-        form.add("client_id", "8bIDtZnH6NvRkW2Fq");
+        form.add("client_id", "iBr3LsTCxOj7D2o0A5m");
         form.add("refresh_token", refreshToken);
 
         ClientResponse response = resource().path("oauth2").path("token")
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2OpenIdControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2OpenIdControllerTest.java
index eb716ab..abb44d7 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2OpenIdControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2OpenIdControllerTest.java
@@ -103,8 +103,6 @@
         assertEquals("thisIsMyState", params.getFirst("state"));
     }
 
-
-
     private void testRequestAuthorizationCodeWithoutOpenID (
             MultivaluedMap<String, String> form, String redirectUri)
             throws KustvaktException {
@@ -350,14 +348,13 @@
         assertEquals(nonce, claimsSet.getClaim("nonce"));
     }
 
-
     // no openid
     @Test
     public void testRequestAccessTokenWithPassword ()
             throws KustvaktException, ParseException, InvalidKeySpecException,
             NoSuchAlgorithmException, JOSEException {
         // public client
-        String client_id = "iBr3LsTCxOj7D2o0A5m";
+        String client_id = "8bIDtZnH6NvRkW2Fq";
         MultivaluedMap<String, String> tokenForm = new MultivaluedMapImpl();
         testRequestAccessTokenMissingGrant(tokenForm);
 
@@ -373,13 +370,12 @@
         ClientResponse tokenResponse = sendTokenRequest(tokenForm);
         String entity = tokenResponse.getEntity(String.class);
         JsonNode node = JsonUtils.readTree(entity);
-        assertNotNull(node.at("/access_token").asText());
-        assertNotNull(node.at("/refresh_token").asText());
-        assertEquals(TokenType.BEARER.toString(),
-                node.at("/token_type").asText());
-        assertNotNull(node.at("/expires_in").asText());
-    }
 
+        assertEquals(OAuth2Error.UNAUTHORIZED_CLIENT,
+                node.at("/error").asText());
+        assertEquals("Password grant is not allowed for third party clients",
+                node.at("/error_description").asText());
+    }
 
     private void testRequestAccessTokenMissingUsername (
             MultivaluedMap<String, String> tokenForm) throws KustvaktException {