Added new APIs: list user-installed plugins and uninstall plugin.
Moved install and list plugin APIs to PluginController and updated their
service paths under /plugins.
Change-Id: I592408665672d52e2479671b97de5ba49e9a9c5a
diff --git a/core/Changes b/core/Changes
index 6a157f5..87d954c 100644
--- a/core/Changes
+++ b/core/Changes
@@ -1,6 +1,6 @@
# version 0.68
- - Added OAuth2 scope: INSTALL_USER_CLIENT
+ - Added OAuth2 scopes: INSTALL_USER_CLIENT, UNINSTALL_USER_CLIENT
- Added status codes
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 915efb5..d6b58ce 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
@@ -15,6 +15,7 @@
LIST_USER_CLIENT,
INSTALL_USER_CLIENT,
+ UNINSTALL_USER_CLIENT,
CLIENT_INFO,
REGISTER_CLIENT,
diff --git a/full/Changes b/full/Changes
index 4f7de42..b179a17 100644
--- a/full/Changes
+++ b/full/Changes
@@ -13,6 +13,10 @@
- Updated redirect URI error message for coherence
2022-05-27
- Added maximum limit to custom refresh token expiry
+2022-06-01
+ - Added new APIs: list user-installed plugins and uninstall plugin.
+ - Moved install and list plugin APIs to PluginController and updated their
+ service paths under /plugins.
# version 0.67.1
diff --git a/full/src/main/java/de/ids_mannheim/korap/dto/InstalledPluginDto.java b/full/src/main/java/de/ids_mannheim/korap/dto/InstalledPluginDto.java
index 1c9943f..eb17a8e 100644
--- a/full/src/main/java/de/ids_mannheim/korap/dto/InstalledPluginDto.java
+++ b/full/src/main/java/de/ids_mannheim/korap/dto/InstalledPluginDto.java
@@ -20,6 +20,8 @@
private String name;
private String description;
private String url;
+ @JsonProperty("redirect_uri")
+ private String redirectUri;
@JsonProperty("installed_date")
private String installedDate;
@@ -31,5 +33,6 @@
setName(client.getName());
setDescription(client.getDescription());
setUrl(client.getUrl());
+ setRedirectUri(client.getRedirectURI());
}
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/entity/InstalledPlugin.java b/full/src/main/java/de/ids_mannheim/korap/entity/InstalledPlugin.java
index b49b1b4..92ab0f9 100644
--- a/full/src/main/java/de/ids_mannheim/korap/entity/InstalledPlugin.java
+++ b/full/src/main/java/de/ids_mannheim/korap/entity/InstalledPlugin.java
@@ -20,7 +20,7 @@
@Getter
@Entity
@Table(name = "installed_plugin")
-public class InstalledPlugin {
+public class InstalledPlugin implements Comparable<InstalledPlugin>{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@@ -38,4 +38,9 @@
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "super_client_id")
private OAuth2Client superClient;
+
+ @Override
+ public int compareTo (InstalledPlugin o) {
+ return this.client.compareTo(o.client);
+ }
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/InstalledPluginDao.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/InstalledPluginDao.java
index 46ac078..00243ba 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/InstalledPluginDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/InstalledPluginDao.java
@@ -2,14 +2,15 @@
import java.time.ZoneId;
import java.time.ZonedDateTime;
+import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
+import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
-import javax.persistence.criteria.Join;
import javax.persistence.criteria.Root;
import org.springframework.stereotype.Repository;
@@ -56,17 +57,15 @@
builder.createQuery(InstalledPlugin.class);
Root<InstalledPlugin> root = query.from(InstalledPlugin.class);
- Join<InstalledPlugin, OAuth2Client> client =
- root.join(InstalledPlugin_.client);
- Join<InstalledPlugin, OAuth2Client> superClient =
- root.join(InstalledPlugin_.superClient);
query.select(root);
query.where(builder.and(
builder.equal(root.get(InstalledPlugin_.INSTALLED_BY),
installedBy),
- builder.equal(client.get(OAuth2Client_.id), clientId),
- builder.equal(superClient.get(OAuth2Client_.id),
- superClientId)));
+ builder.equal(
+ root.get(InstalledPlugin_.client).get(OAuth2Client_.id),
+ clientId),
+ builder.equal(root.get(InstalledPlugin_.superClient)
+ .get(OAuth2Client_.id), superClientId)));
Query q = entityManager.createQuery(query);
try {
@@ -76,4 +75,38 @@
throw new KustvaktException(StatusCodes.NO_RESOURCE_FOUND);
}
}
+
+ public List<InstalledPlugin> retrieveInstalledPlugins (String superClientId,
+ String installedBy) throws KustvaktException {
+ ParameterChecker.checkStringValue(superClientId, "super_client_id");
+ ParameterChecker.checkStringValue(installedBy, "installedBy");
+
+ CriteriaBuilder builder = entityManager.getCriteriaBuilder();
+ CriteriaQuery<InstalledPlugin> query =
+ builder.createQuery(InstalledPlugin.class);
+
+ Root<InstalledPlugin> root = query.from(InstalledPlugin.class);
+ query.select(root);
+ query.where(builder.and(
+ builder.equal(root.get(InstalledPlugin_.INSTALLED_BY),
+ installedBy),
+ builder.equal(root.get(InstalledPlugin_.superClient)
+ .get(OAuth2Client_.id), superClientId)));
+
+ TypedQuery<InstalledPlugin> q = entityManager.createQuery(query);
+ try {
+ return q.getResultList();
+ }
+ catch (NoResultException e) {
+ throw new KustvaktException(StatusCodes.NO_RESOURCE_FOUND);
+ }
+ }
+
+ public void uninstallPlugin (String superClientId, String clientId,
+ String username) throws KustvaktException {
+ InstalledPlugin plugin =
+ retrieveInstalledPlugin(superClientId, clientId, username);
+ entityManager.remove(plugin);
+ }
+
}
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 076a762..30e1196 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
@@ -481,7 +481,7 @@
return revokeRefreshToken(refreshToken);
}
- private boolean revokeRefreshToken (RefreshToken refreshToken)
+ public boolean revokeRefreshToken (RefreshToken refreshToken)
throws KustvaktException {
if (refreshToken != null){
refreshToken.setRevoked(true);
@@ -511,6 +511,11 @@
}
String clientId = revokeTokenRequest.getClientId();
+ revokeAllClientTokensForUser(clientId, username);
+ }
+
+ public void revokeAllClientTokensForUser (String clientId, String username)
+ throws KustvaktException {
OAuth2Client client = clientService.retrieveClient(clientId);
if (clientService.isPublicClient(client)) {
List<AccessToken> accessTokens =
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 47ba029..4fee392 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
@@ -34,6 +34,7 @@
import de.ids_mannheim.korap.oauth2.entity.Authorization;
import de.ids_mannheim.korap.oauth2.entity.OAuth2Client;
import de.ids_mannheim.korap.oauth2.entity.RefreshToken;
+import de.ids_mannheim.korap.oauth2.oltu.service.OltuTokenService;
import de.ids_mannheim.korap.utils.ParameterChecker;
import de.ids_mannheim.korap.web.input.OAuth2ClientJson;
@@ -65,6 +66,8 @@
// UrlValidator.NO_FRAGMENTS + UrlValidator.ALLOW_LOCAL_URLS);
@Autowired
+ private OltuTokenService tokenService;
+ @Autowired
private InstalledPluginDao pluginDao;
@Autowired
private OAuth2ClientDao clientDao;
@@ -390,12 +393,24 @@
return createClientDtos(plugins);
}
+ public List<InstalledPluginDto> listInstalledPlugins (String superClientId,
+ String username) throws KustvaktException {
+
+ List<InstalledPlugin> plugins =
+ pluginDao.retrieveInstalledPlugins(superClientId, username);
+ Collections.sort(plugins); // by client name
+
+ List<InstalledPluginDto> list = new ArrayList<InstalledPluginDto>(plugins.size());
+ for (InstalledPlugin p : plugins) {
+ list.add(new InstalledPluginDto(p));
+ }
+
+ return list;
+ }
+
public InstalledPluginDto installPlugin (String superClientId,
String clientId, String installedBy) throws KustvaktException {
- if (clientId == null || clientId.isEmpty()) {
- throw new KustvaktException(StatusCodes.MISSING_PARAMETER,
- "Missing parameter: client_id");
- }
+
OAuth2Client client = clientDao.retrieveClientById(clientId);
if (!client.isPermitted()) {
throw new KustvaktException(StatusCodes.PLUGIN_NOT_PERMITTED,
@@ -414,6 +429,12 @@
InstalledPluginDto dto = new InstalledPluginDto(plugin);
return dto;
}
+
+ public void uninstallPlugin (String superClientId,
+ String clientId, String username) throws KustvaktException {
+ pluginDao.uninstallPlugin(superClientId, clientId, username);
+ tokenService.revokeAllClientTokensForUser(clientId, username);
+ }
private boolean isPluginInstalled (String superClientId, String clientId,
String installedBy) {
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuthClientController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuthClientController.java
index ed380d9..8ffc164 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuthClientController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuthClientController.java
@@ -231,53 +231,4 @@
throw responseHandler.throwit(e);
}
}
-
- @POST
- @Path("/plugins")
- @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
- @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
- public List<OAuth2ClientInfoDto> listPlugins (
- @Context SecurityContext context,
- @FormParam("super_client_id") String superClientId,
- @FormParam("super_client_secret") String superClientSecret,
- @FormParam("permitted_only") boolean permittedOnly) {
-
- TokenContext tokenContext = (TokenContext) context.getUserPrincipal();
-
- try {
- scopeService.verifyScope(tokenContext,
- OAuth2Scope.LIST_USER_CLIENT);
-
- clientService.verifySuperClient(superClientId, superClientSecret);
- return clientService.listPlugins(permittedOnly);
- }
- catch (KustvaktException e) {
- throw responseHandler.throwit(e);
- }
- }
-
- @POST
- @Path("/install")
- @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
- @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
- public InstalledPluginDto installPlugin (
- @Context SecurityContext context,
- @FormParam("super_client_id") String superClientId,
- @FormParam("super_client_secret") String superClientSecret,
- @FormParam("client_id") String clientId) {
-
- TokenContext tokenContext = (TokenContext) context.getUserPrincipal();
- String username = tokenContext.getUsername();
-
- try {
- scopeService.verifyScope(tokenContext,
- OAuth2Scope.INSTALL_USER_CLIENT);
-
- clientService.verifySuperClient(superClientId, superClientSecret);
- return clientService.installPlugin(superClientId,clientId, username);
- }
- catch (KustvaktException e) {
- throw responseHandler.throwit(e);
- }
- }
}
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/PluginController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/PluginController.java
new file mode 100644
index 0000000..581b325
--- /dev/null
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/PluginController.java
@@ -0,0 +1,141 @@
+package de.ids_mannheim.korap.web.controller;
+
+import java.util.List;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.POST;
+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.Response;
+import javax.ws.rs.core.SecurityContext;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+
+import com.sun.jersey.spi.container.ResourceFilters;
+
+import de.ids_mannheim.korap.constant.OAuth2Scope;
+import de.ids_mannheim.korap.dto.InstalledPluginDto;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.oauth2.dto.OAuth2ClientInfoDto;
+import de.ids_mannheim.korap.oauth2.service.OAuth2ClientService;
+import de.ids_mannheim.korap.oauth2.service.OAuth2ScopeService;
+import de.ids_mannheim.korap.security.context.TokenContext;
+import de.ids_mannheim.korap.web.OAuth2ResponseHandler;
+import de.ids_mannheim.korap.web.filter.APIVersionFilter;
+import de.ids_mannheim.korap.web.filter.AuthenticationFilter;
+import de.ids_mannheim.korap.web.filter.BlockingFilter;
+
+@Controller
+@Path("{version}/plugins")
+@ResourceFilters({ APIVersionFilter.class, AuthenticationFilter.class,
+ BlockingFilter.class })
+public class PluginController {
+
+ @Autowired
+ private OAuth2ScopeService scopeService;
+ @Autowired
+ private OAuth2ClientService clientService;
+ @Autowired
+ private OAuth2ResponseHandler responseHandler;
+
+ @POST
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
+ public List<OAuth2ClientInfoDto> listPlugins (
+ @Context SecurityContext context,
+ @FormParam("super_client_id") String superClientId,
+ @FormParam("super_client_secret") String superClientSecret,
+ @FormParam("permitted_only") boolean permittedOnly) {
+
+ TokenContext tokenContext = (TokenContext) context.getUserPrincipal();
+
+ try {
+ scopeService.verifyScope(tokenContext,
+ OAuth2Scope.LIST_USER_CLIENT);
+
+ clientService.verifySuperClient(superClientId, superClientSecret);
+ return clientService.listPlugins(permittedOnly);
+ }
+ catch (KustvaktException e) {
+ throw responseHandler.throwit(e);
+ }
+ }
+
+ @POST
+ @Path("/install")
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
+ public InstalledPluginDto installPlugin (
+ @Context SecurityContext context,
+ @FormParam("super_client_id") String superClientId,
+ @FormParam("super_client_secret") String superClientSecret,
+ @FormParam("client_id") String clientId) {
+
+ TokenContext tokenContext = (TokenContext) context.getUserPrincipal();
+ String username = tokenContext.getUsername();
+
+ try {
+ scopeService.verifyScope(tokenContext,
+ OAuth2Scope.INSTALL_USER_CLIENT);
+
+ clientService.verifySuperClient(superClientId, superClientSecret);
+ return clientService.installPlugin(superClientId,clientId, username);
+ }
+ catch (KustvaktException e) {
+ throw responseHandler.throwit(e);
+ }
+ }
+
+ @POST
+ @Path("/installed")
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
+ public List<InstalledPluginDto> listInstalledPlugins (
+ @Context SecurityContext context,
+ @FormParam("super_client_id") String superClientId,
+ @FormParam("super_client_secret") String superClientSecret) {
+
+ TokenContext tokenContext = (TokenContext) context.getUserPrincipal();
+
+ try {
+ scopeService.verifyScope(tokenContext,
+ OAuth2Scope.LIST_USER_CLIENT);
+
+ clientService.verifySuperClient(superClientId, superClientSecret);
+ return clientService.listInstalledPlugins(superClientId,
+ tokenContext.getUsername());
+ }
+ catch (KustvaktException e) {
+ throw responseHandler.throwit(e);
+ }
+ }
+
+ @POST
+ @Path("/uninstall")
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ public Response uninstallPlugin (
+ @Context SecurityContext context,
+ @FormParam("super_client_id") String superClientId,
+ @FormParam("super_client_secret") String superClientSecret,
+ @FormParam("client_id") String clientId) {
+
+ TokenContext tokenContext = (TokenContext) context.getUserPrincipal();
+ String username = tokenContext.getUsername();
+
+ try {
+ scopeService.verifyScope(tokenContext,
+ OAuth2Scope.UNINSTALL_USER_CLIENT);
+
+ clientService.verifySuperClient(superClientId, superClientSecret);
+ clientService.uninstallPlugin(superClientId,clientId, username);
+ return Response.ok().build();
+ }
+ catch (KustvaktException e) {
+ throw responseHandler.throwit(e);
+ }
+ }
+}
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 eeae3b7..2473d21 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
@@ -138,17 +138,6 @@
node.at("/errors/0/1").asText());
}
- private void testSearchWithOAuth2Token (String accessToken)
- throws KustvaktException, IOException {
- ClientResponse response = searchWithAccessToken(accessToken);
- String entity = response.getEntity(String.class);
- assertEquals(ClientResponse.Status.OK.getStatusCode(),
- response.getStatus());
- JsonNode node = JsonUtils.readTree(entity);
- assertNotNull(node);
- assertEquals(25, node.at("/matches").size());
- }
-
@Test
public void testSearchWithUnknownToken ()
throws KustvaktException, IOException {
@@ -204,20 +193,6 @@
testSearchWithRevokedAccessToken(accessToken);
}
- private void testSearchWithRevokedAccessToken (String accessToken)
- throws KustvaktException {
- ClientResponse response = searchWithAccessToken(accessToken);
- String entity = response.getEntity(String.class);
- assertEquals(ClientResponse.Status.UNAUTHORIZED.getStatusCode(),
- response.getStatus());
-
- JsonNode node = JsonUtils.readTree(entity);
- assertEquals(StatusCodes.INVALID_ACCESS_TOKEN,
- node.at("/errors/0/0").asInt());
- assertEquals("Access token is invalid",
- node.at("/errors/0/1").asText());
- }
-
@Test
public void testAccessTokenAfterRequestRefreshToken ()
throws KustvaktException, IOException {
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2AdminControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2AdminControllerTest.java
index 958542b..789c2d9 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2AdminControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2AdminControllerTest.java
@@ -138,7 +138,7 @@
updateClientPriviledge(clientId, false);
testAccessTokenAfterDegradingSuperClient(clientId, accessToken);
- deregisterConfidentialClient(username, clientId);
+ deregisterClient(username, clientId);
}
// old access tokens retain their scopes
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 fc1e24c..02b9ba1 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
@@ -125,7 +125,7 @@
testListConfidentialClient(username, clientId);
testConfidentialClientInfo(clientId, username);
testResetConfidentialClientSecret(clientId, clientSecret);
- deregisterConfidentialClient(username, clientId);
+ deregisterClient(username, clientId);
}
@Test
@@ -265,7 +265,7 @@
JsonNode clientInfo = retrieveClientInfo(clientId, username);
assertEquals(expiry, clientInfo.at("/refresh_token_expiry").asInt());
- deregisterConfidentialClient(username, clientId);
+ deregisterClient(username, clientId);
}
@Test
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2PluginTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2PluginTest.java
index 34081a5..a3f567b 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2PluginTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2PluginTest.java
@@ -5,6 +5,8 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import java.io.IOException;
+
import javax.ws.rs.core.MultivaluedMap;
import org.apache.http.entity.ContentType;
@@ -36,7 +38,6 @@
private String username = "plugin-user";
@Autowired
private InstalledPluginDao pluginDao;
-
@Test
public void testRegisterPlugin () throws UniformInterfaceException,
@@ -44,7 +45,7 @@
JsonNode source = JsonUtils.readTree("{ \"plugin\" : \"source\"}");
int refreshTokenExpiry = TimeUtils.convertTimeToSeconds("90D");
-
+
String clientName = "Plugin";
OAuth2ClientJson json = new OAuth2ClientJson();
json.setName(clientName);
@@ -60,9 +61,9 @@
String clientSecret = node.at("/client_secret").asText();
assertNotNull(clientId);
assertNotNull(clientSecret);
-
+
testInstallPluginNotPermitted(clientId);
- testRetrievePluginInfo(clientId,refreshTokenExpiry);
+ testRetrievePluginInfo(clientId, refreshTokenExpiry);
node = listPlugins(false);
assertEquals(3, node.size());
@@ -71,12 +72,32 @@
testListUserRegisteredPlugins(username, clientId, clientName,
refreshTokenExpiry);
- deregisterConfidentialClient(username, clientId);
+ deregisterClient(username, clientId);
}
- private void testRetrievePluginInfo (String clientId, int refreshTokenExpiry)
- throws UniformInterfaceException, ClientHandlerException,
- KustvaktException {
+ @Test
+ public void testRegisterPublicPlugin () throws KustvaktException {
+ JsonNode source = JsonUtils.readTree("{ \"plugin\" : \"source\"}");
+ String clientName = "Public Plugin";
+ OAuth2ClientJson json = new OAuth2ClientJson();
+ json.setName(clientName);
+ json.setType(OAuth2ClientType.PUBLIC);
+ json.setDescription("This is a public plugin.");
+ json.setSource(source);
+
+ ClientResponse response = registerClient(username, json);
+ assertEquals(Status.OK.getStatusCode(), response.getStatus());
+ JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
+
+ String clientId = node.at("/client_id").asText();
+ assertTrue(node.at("/client_secret").isMissingNode());
+
+ deregisterClient(username, clientId);
+ }
+
+ private void testRetrievePluginInfo (String clientId,
+ int refreshTokenExpiry) throws UniformInterfaceException,
+ ClientHandlerException, KustvaktException {
JsonNode clientInfo = retrieveClientInfo(clientId, username);
assertEquals(clientId, clientInfo.at("/client_id").asText());
assertEquals("Plugin", clientInfo.at("/client_name").asText());
@@ -136,8 +157,7 @@
MultivaluedMap<String, String> form = new MultivaluedMapImpl();
form.add("super_client_id", confidentialClientId);
- ClientResponse response = resource().path(API_VERSION).path("oauth2")
- .path("client").path("plugins")
+ ClientResponse response = resource().path(API_VERSION).path("plugins")
.header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
.createBasicAuthorizationHeaderValue(username, "pass"))
.header(HttpHeaders.CONTENT_TYPE,
@@ -157,8 +177,7 @@
MultivaluedMap<String, String> form)
throws UniformInterfaceException, ClientHandlerException,
KustvaktException {
- ClientResponse response = resource().path(API_VERSION).path("oauth2")
- .path("client").path("plugins")
+ ClientResponse response = resource().path(API_VERSION).path("plugins")
.header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
.createBasicAuthorizationHeaderValue(username, "pass"))
.header(HttpHeaders.CONTENT_TYPE,
@@ -180,8 +199,7 @@
throws UniformInterfaceException, ClientHandlerException,
KustvaktException {
- ClientResponse response = resource().path(API_VERSION).path("oauth2")
- .path("client").path("plugins")
+ ClientResponse response = resource().path(API_VERSION).path("plugins")
.header(Attributes.AUTHORIZATION, "Bearer blahblah")
.header(HttpHeaders.CONTENT_TYPE,
ContentType.APPLICATION_FORM_URLENCODED)
@@ -189,7 +207,7 @@
String entity = response.getEntity(String.class);
JsonNode node = JsonUtils.readTree(entity);
-
+
assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
assertEquals(StatusCodes.INVALID_ACCESS_TOKEN,
node.at("/errors/0/0").asInt());
@@ -209,7 +227,7 @@
assertFalse(node.at("/0/source").isMissingNode());
assertFalse(node.at("/0/refresh_token_expiry").isMissingNode());
-// assertTrue(node.at("/1/refresh_token_expiry").isMissingNode());
+ // assertTrue(node.at("/1/refresh_token_expiry").isMissingNode());
}
private JsonNode listPlugins (boolean permitted_only)
@@ -220,8 +238,7 @@
if (permitted_only) {
form.add("permitted_only", Boolean.toString(permitted_only));
}
- ClientResponse response = resource().path(API_VERSION).path("oauth2")
- .path("client").path("plugins")
+ ClientResponse response = resource().path(API_VERSION).path("plugins")
.header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
.createBasicAuthorizationHeaderValue(username, "pass"))
.header(HttpHeaders.CONTENT_TYPE,
@@ -234,54 +251,57 @@
return JsonUtils.readTree(entity);
}
- @Test
- public void testInstallConfidentialPlugin () throws UniformInterfaceException,
+ private void testInstallConfidentialPlugin (String superClientId,
+ String clientId, String username) throws UniformInterfaceException,
ClientHandlerException, KustvaktException {
MultivaluedMap<String, String> form = getSuperClientForm();
- form.add("client_id", confidentialClientId2);
+ form.add("client_id", clientId);
ClientResponse response = installPlugin(form);
-
+
String entity = response.getEntity(String.class);
JsonNode node = JsonUtils.readTree(entity);
- assertEquals(confidentialClientId2, node.at("/client_id").asText());
+ assertEquals(clientId, node.at("/client_id").asText());
assertEquals(superClientId, node.at("/super_client_id").asText());
-
+
assertFalse(node.at("/name").isMissingNode());
assertFalse(node.at("/description").isMissingNode());
assertFalse(node.at("/url").isMissingNode());
assertFalse(node.at("/installed_date").isMissingNode());
assertEquals(Status.OK.getStatusCode(), response.getStatus());
-
- testRetrieveInstalledPlugin(superClientId, confidentialClientId2,
- username);
+
+ testRetrieveInstalledPlugin(superClientId, clientId, username);
}
-
+
@Test
public void testInstallPublicPlugin () throws UniformInterfaceException,
ClientHandlerException, KustvaktException {
MultivaluedMap<String, String> form = getSuperClientForm();
form.add("client_id", publicClientId2);
ClientResponse response = installPlugin(form);
-
+
String entity = response.getEntity(String.class);
JsonNode node = JsonUtils.readTree(entity);
assertEquals(publicClientId2, node.at("/client_id").asText());
assertEquals(superClientId, node.at("/super_client_id").asText());
-
+
assertFalse(node.at("/name").isMissingNode());
assertFalse(node.at("/description").isMissingNode());
assertFalse(node.at("/url").isMissingNode());
assertFalse(node.at("/installed_date").isMissingNode());
-
+
assertEquals(Status.OK.getStatusCode(), response.getStatus());
-
+
testInstallPluginRedundant(form);
-
- testRetrieveInstalledPlugin(superClientId, publicClientId2,
- username);
+
+ testRetrieveInstalledPlugin(superClientId, publicClientId2, username);
+
+ response = uninstallPlugin(publicClientId2, username);
+ assertEquals(Status.OK.getStatusCode(), response.getStatus());
+ node = retrieveUserInstalledPlugin(getSuperClientForm());
+ assertTrue(node.isEmpty());
}
-
+
private void testInstallPluginRedundant (
MultivaluedMap<String, String> form)
throws UniformInterfaceException, ClientHandlerException,
@@ -306,21 +326,24 @@
node.at("/errors/0/0").asInt());
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
}
-
+
@Test
- public void testInstallPluginMissingClientId () throws UniformInterfaceException,
- ClientHandlerException, KustvaktException {
+ public void testInstallPluginMissingClientId ()
+ throws UniformInterfaceException, ClientHandlerException,
+ KustvaktException {
MultivaluedMap<String, String> form = getSuperClientForm();
ClientResponse response = installPlugin(form);
String entity = response.getEntity(String.class);
JsonNode node = JsonUtils.readTree(entity);
- assertEquals(StatusCodes.MISSING_PARAMETER, node.at("/errors/0/0").asInt());
+ assertEquals(StatusCodes.INVALID_ARGUMENT,
+ node.at("/errors/0/0").asInt());
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
}
-
+
@Test
- public void testInstallPluginInvalidClientId () throws UniformInterfaceException,
- ClientHandlerException, KustvaktException {
+ public void testInstallPluginInvalidClientId ()
+ throws UniformInterfaceException, ClientHandlerException,
+ KustvaktException {
MultivaluedMap<String, String> form = getSuperClientForm();
form.add("client_id", "unknown");
ClientResponse response = installPlugin(form);
@@ -331,24 +354,25 @@
assertEquals("invalid_client", node.at("/error").asText());
assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
}
-
+
@Test
- public void testInstallPluginMissingSuperClientSecret () throws UniformInterfaceException,
- ClientHandlerException, KustvaktException {
+ public void testInstallPluginMissingSuperClientSecret ()
+ throws UniformInterfaceException, ClientHandlerException,
+ KustvaktException {
MultivaluedMap<String, String> form = new MultivaluedMapImpl();
form.add("super_client_id", superClientId);
-
+
ClientResponse response = installPlugin(form);
String entity = response.getEntity(String.class);
JsonNode node = JsonUtils.readTree(entity);
-
+
assertEquals("Missing parameter: super_client_secret",
node.at("/error_description").asText());
assertEquals("invalid_request", node.at("/error").asText());
-
+
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
}
-
+
@Test
public void testInstallPluginMissingSuperClientId ()
throws UniformInterfaceException, ClientHandlerException,
@@ -364,7 +388,7 @@
assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
}
-
+
@Test
public void testInstallPluginUnauthorizedClient ()
throws UniformInterfaceException, ClientHandlerException,
@@ -372,27 +396,41 @@
MultivaluedMap<String, String> form = new MultivaluedMapImpl();
form.add("super_client_id", confidentialClientId);
form.add("super_client_secret", clientSecret);
-
+
ClientResponse response = installPlugin(form);
String entity = response.getEntity(String.class);
JsonNode node = JsonUtils.readTree(entity);
assertEquals("unauthorized_client", node.at("/error").asText());
-
+
assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
}
private ClientResponse installPlugin (MultivaluedMap<String, String> form)
throws UniformInterfaceException, ClientHandlerException,
KustvaktException {
- return resource().path(API_VERSION).path("oauth2").path("client")
- .path("install")
+ return resource().path(API_VERSION).path("plugins").path("install")
.header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
.createBasicAuthorizationHeaderValue(username, "pass"))
.header(HttpHeaders.CONTENT_TYPE,
ContentType.APPLICATION_FORM_URLENCODED)
.entity(form).post(ClientResponse.class);
}
-
+
+ private ClientResponse uninstallPlugin (String clientId, String username)
+ throws UniformInterfaceException, ClientHandlerException,
+ KustvaktException {
+
+ MultivaluedMap<String, String> form = getSuperClientForm();
+ form.add("client_id", clientId);
+
+ return resource().path(API_VERSION).path("plugins").path("uninstall")
+ .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
+ .createBasicAuthorizationHeaderValue(username, "pass"))
+ .header(HttpHeaders.CONTENT_TYPE,
+ ContentType.APPLICATION_FORM_URLENCODED)
+ .entity(form).post(ClientResponse.class);
+ }
+
private void testRetrieveInstalledPlugin (String superClientId,
String clientId, String installedBy) throws KustvaktException {
InstalledPlugin plugin = pluginDao
@@ -400,8 +438,86 @@
assertEquals(clientId, plugin.getClient().getId());
assertEquals(superClientId, plugin.getSuperClient().getId());
assertEquals(installedBy, plugin.getInstalledBy());
+
+ assertTrue(plugin.getId() > 0);
+ assertTrue(plugin.getInstalledDate() != null);
+ }
+
+ @Test
+ public void testListUserInstalledPlugins ()
+ throws UniformInterfaceException, ClientHandlerException,
+ KustvaktException, IOException {
+
+ testInstallConfidentialPlugin(superClientId, confidentialClientId,
+ username);
- assertTrue(plugin.getId()>0);
- assertTrue(plugin.getInstalledDate()!= null);
+ JsonNode node = testRequestAccessToken(confidentialClientId);
+ String accessToken = node.at("/access_token").asText();
+ String refreshToken = node.at("/refresh_token").asText();
+ testSearchWithOAuth2Token(accessToken);
+
+ testInstallConfidentialPlugin(superClientId, confidentialClientId2,
+ username);
+
+ node = retrieveUserInstalledPlugin(getSuperClientForm());
+ assertEquals(2, node.size());
+
+ ClientResponse response =
+ uninstallPlugin(confidentialClientId, username);
+ assertEquals(Status.OK.getStatusCode(), response.getStatus());
+ node = retrieveUserInstalledPlugin(getSuperClientForm());
+ assertEquals(1, node.size());
+
+ testRequestTokenWithRevokedRefreshToken(confidentialClientId,
+ clientSecret, refreshToken);
+ testSearchWithRevokedAccessToken(accessToken);
+
+ response = uninstallPlugin(confidentialClientId2, username);
+ assertEquals(Status.OK.getStatusCode(), response.getStatus());
+ node = retrieveUserInstalledPlugin(getSuperClientForm());
+ assertEquals(0, node.size());
+
+ testUninstallNotInstalledPlugin();
+ }
+
+ private JsonNode testRequestAccessToken (String clientId) throws KustvaktException {
+ String userAuthHeader = HttpAuthorizationHandler
+ .createBasicAuthorizationHeaderValue(username, "password");
+ String code = requestAuthorizationCode(clientId, userAuthHeader);
+ ClientResponse response = requestTokenWithAuthorizationCodeAndForm(
+ clientId, clientSecret, code);
+ JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
+
+ assertEquals(Status.OK.getStatusCode(), response.getStatus());
+ return node;
+ }
+
+ private void testUninstallNotInstalledPlugin ()
+ throws UniformInterfaceException, ClientHandlerException,
+ KustvaktException {
+ ClientResponse response =
+ uninstallPlugin(confidentialClientId2, username);
+ assertEquals(Status.NOT_FOUND.getStatusCode(), response.getStatus());
+ JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
+ assertEquals(StatusCodes.NO_RESOURCE_FOUND,
+ node.at("/errors/0/0").asInt());
+
+ }
+
+ private JsonNode retrieveUserInstalledPlugin (
+ MultivaluedMap<String, String> form)
+ throws UniformInterfaceException, ClientHandlerException,
+ KustvaktException {
+ ClientResponse response = resource().path(API_VERSION).path("plugins")
+ .path("installed")
+ .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler
+ .createBasicAuthorizationHeaderValue(username, "pass"))
+ .header(HttpHeaders.CONTENT_TYPE,
+ ContentType.APPLICATION_FORM_URLENCODED)
+ .entity(form).post(ClientResponse.class);
+
+ String entity = response.getEntity(String.class);
+ return JsonUtils.readTree(entity);
+
}
}
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2TestBase.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2TestBase.java
index 6526190..9b3d506 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2TestBase.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2TestBase.java
@@ -4,6 +4,7 @@
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;
@@ -29,6 +30,7 @@
import de.ids_mannheim.korap.config.Attributes;
import de.ids_mannheim.korap.config.SpringJerseyTest;
import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
import de.ids_mannheim.korap.oauth2.constant.OAuth2ClientType;
import de.ids_mannheim.korap.oauth2.constant.OAuth2Error;
import de.ids_mannheim.korap.oauth2.dao.RefreshTokenDao;
@@ -287,7 +289,7 @@
}
- protected void deregisterConfidentialClient (String username,
+ protected void deregisterClient (String username,
String clientId) throws UniformInterfaceException,
ClientHandlerException, KustvaktException {
@@ -322,6 +324,32 @@
.header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
.get(ClientResponse.class);
}
+
+ protected void testSearchWithOAuth2Token (String accessToken)
+ throws KustvaktException, IOException {
+ ClientResponse response = searchWithAccessToken(accessToken);
+ String entity = response.getEntity(String.class);
+ assertEquals(ClientResponse.Status.OK.getStatusCode(),
+ response.getStatus());
+ JsonNode node = JsonUtils.readTree(entity);
+ assertNotNull(node);
+ assertEquals(25, node.at("/matches").size());
+ }
+
+ protected void testSearchWithRevokedAccessToken (String accessToken)
+ throws KustvaktException {
+ ClientResponse response = searchWithAccessToken(accessToken);
+ String entity = response.getEntity(String.class);
+ assertEquals(ClientResponse.Status.UNAUTHORIZED.getStatusCode(),
+ response.getStatus());
+
+ JsonNode node = JsonUtils.readTree(entity);
+ assertEquals(StatusCodes.INVALID_ACCESS_TOKEN,
+ node.at("/errors/0/0").asInt());
+ assertEquals("Access token is invalid",
+ node.at("/errors/0/1").asText());
+ }
+
protected void testRevokeTokenViaSuperClient (String token,
String userAuthHeader) {