Updated OAuth2 refresh token request to create a new refresh token.

Change-Id: Ia08d037193c796d549a4434c3ac5bdf66f362cd8
diff --git a/full/Changes b/full/Changes
index 647f863..b8d1645 100644
--- a/full/Changes
+++ b/full/Changes
@@ -1,6 +1,9 @@
 # version 0.61.4
 14/11/2018
    - Integrated lite and full services and controllers in core (margaretha)
+21/11/2018
+   - Updated OAuth2 refresh token request to create a new refresh token and 
+     revoke the old one per request (margaretha)   
    
 # version 0.61.3
 17/10/2018
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 e73421b..6bf3b39 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
@@ -25,7 +25,6 @@
 import de.ids_mannheim.korap.oauth2.dao.AccessTokenDao;
 import de.ids_mannheim.korap.oauth2.dao.RefreshTokenDao;
 import de.ids_mannheim.korap.oauth2.entity.AccessScope;
-import de.ids_mannheim.korap.oauth2.entity.AccessScope;
 import de.ids_mannheim.korap.oauth2.entity.AccessToken;
 import de.ids_mannheim.korap.oauth2.entity.Authorization;
 import de.ids_mannheim.korap.oauth2.entity.OAuth2Client;
@@ -80,14 +79,16 @@
 
     /**
      * Revokes all access token associated with the given refresh
-     * token, and creates a new access token with the given refresh
-     * token and scopes. Thus, at one point of time, there is only one
-     * active access token associated with a refresh token.
+     * token, and creates a new access token and a new refresh
+     * token with the same scopes. Thus, at one point of time,
+     * there is only one active access token associated with
+     * a refresh token.
      * 
      * Client authentication is done using the given client
      * credentials.
      * 
-     * TODO: should create a new refresh token when the old refresh token is used
+     * TODO: should create a new refresh token when the old refresh
+     * token is used
      * 
      * @param refreshTokenStr
      * @param scopes
@@ -139,11 +140,23 @@
         if (scopes != null && !scopes.isEmpty()) {
             requestedScopes =
                     scopeService.verifyRefreshScope(scopes, requestedScopes);
+            scopes = scopeService
+                    .convertAccessScopesToStringSet(requestedScopes);
         }
 
+        // revoke the refresh token and all access tokens associated
+        // to it
+        revokeRefreshToken(refreshTokenStr);
+
         return createsAccessTokenResponse(scopes, requestedScopes, clientId,
                 refreshToken.getUserId(),
-                refreshToken.getUserAuthenticationTime(), refreshToken);
+                refreshToken.getUserAuthenticationTime());
+
+        // without new refresh token
+        // return createsAccessTokenResponse(scopes, requestedScopes,
+        // clientId,
+        // refreshToken.getUserId(),
+        // refreshToken.getUserAuthenticationTime(), refreshToken);
     }
 
     /**
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 07d5e5d..674a5e6 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
@@ -222,9 +222,9 @@
 
         node = JsonUtils.readTree(entity);
         assertNotNull(node.at("/access_token").asText());
-        assertEquals(refreshToken, node.at("/refresh_token").asText());
+        assertTrue(!refreshToken.equals(node.at("/refresh_token").asText()));
 
-        testSearchWithOAuth2Token(accessToken);
+        testSearchWithRevokedAccessToken(accessToken);
     }
 
     @Test
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 f16ec74..945e9d0 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
@@ -2,6 +2,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 import java.net.URI;
 
@@ -175,17 +176,16 @@
                 node.at("/token_type").asText());
         assertNotNull(node.at("/expires_in").asText());
 
-        testRevokeTokenPublicClient(accessToken, publicClientId,
+        testRevokeToken(accessToken, publicClientId,null,
                 "access_token");
 
         testRequestRefreshTokenInvalidScope(publicClientId, refreshToken);
-        testRequestRefreshTokenPublicClient(publicClientId, refreshToken);
         testRequestRefreshTokenInvalidClient(refreshToken);
         testRequestRefreshTokenInvalidRefreshToken(publicClientId);
+        testRequestRefreshTokenPublicClient(publicClientId, refreshToken);
 
-        testRevokeTokenPublicClient(refreshToken, publicClientId,
-                "refresh_token");
-        testRequestRefreshWithRevokedRefreshToken(publicClientId, refreshToken);
+        testRequestRefreshWithRevokedRefreshToken(publicClientId, null,
+                refreshToken);
     }
 
     @Test
@@ -218,6 +218,11 @@
         assertNotNull(node.at("/expires_in").asText());
 
         testRequestTokenWithUsedAuthorization(code);
+        
+        String refreshToken = node.at("/refresh_token").asText();
+        testRevokeToken(refreshToken, confidentialClientId,clientSecret,
+                "refresh_token");
+        testRequestRefreshWithRevokedRefreshToken(confidentialClientId, clientSecret, refreshToken);
     }
 
     private void testRequestTokenWithUsedAuthorization (String code)
@@ -585,6 +590,8 @@
         assertEquals(TokenType.BEARER.toString(),
                 node.at("/token_type").asText());
         assertNotNull(node.at("/expires_in").asText());
+
+        assertTrue(!node.at("/refresh_token").asText().equals(refreshToken));
     }
 
     private void testRequestRefreshTokenInvalidClient (String refreshToken)
@@ -624,11 +631,14 @@
     }
 
     private void testRequestRefreshWithRevokedRefreshToken (String clientId,
-            String refreshToken) throws KustvaktException {
+            String clientSecret, String refreshToken) throws KustvaktException {
         MultivaluedMap<String, String> form = new MultivaluedMapImpl();
         form.add("grant_type", GrantType.REFRESH_TOKEN.toString());
         form.add("client_id", clientId);
         form.add("refresh_token", refreshToken);
+        if (clientSecret!=null){
+            form.add("client_secret", clientSecret);
+        }
 
         ClientResponse response = resource().path(API_VERSION).path("oauth2").path("token")
                 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
@@ -641,13 +651,16 @@
         assertEquals(OAuth2Error.INVALID_GRANT, node.at("/error").asText());
     }
 
-    private void testRevokeTokenPublicClient (String token, String clientId,
-            String tokenType) {
+    private void testRevokeToken (String token, String clientId,
+            String clientSecret, String tokenType) {
         MultivaluedMap<String, String> form = new MultivaluedMapImpl();
         form.add("token_type", tokenType);
         form.add("token", token);
         form.add("client_id", clientId);
-
+        if (clientSecret!=null){
+            form.add("client_secret", clientSecret);
+        }
+        
         ClientResponse response = resource().path(API_VERSION).path("oauth2").path("revoke")
                 .header(HttpHeaders.CONTENT_TYPE,
                         ContentType.APPLICATION_FORM_URLENCODED)
@@ -655,5 +668,5 @@
 
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
     }
-
+    
 }