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/main/java/de/ids_mannheim/korap/web/controller/OAuthClientController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/OAuthClientController.java
index 293685e..387194c 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
@@ -3,6 +3,7 @@
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
@@ -17,31 +18,50 @@
 
 import com.sun.jersey.spi.container.ResourceFilters;
 
-import de.ids_mannheim.korap.dto.OAuth2ClientDto;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.oauth2.constant.OAuth2Scope;
+import de.ids_mannheim.korap.oauth2.dto.OAuth2ClientDto;
+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.AuthenticationFilter;
 import de.ids_mannheim.korap.web.filter.BlockingFilter;
 import de.ids_mannheim.korap.web.input.OAuth2ClientJson;
 
-
 /**
  * Defines controllers for OAuth2 clients, namely applications
  * performing actions such as searching and retrieving match
  * information on behalf of users.
  * 
+ * <br /><br />
+ * According to its privileges, clients are categorized into super and
+ * normal clients. Super clients are intended only for clients that
+ * are part of KorAP. They has special privileges to use controllers
+ * that usually are not allowed for normal clients, for instance using
+ * OAuth2 password grant to obtain access tokens.
+ * 
+ * <br /><br />
+ * By default, clients are set as normal clients. Super clients has to
+ * be set manually by an admin, e.g by using
+ * {@link #updateClientPrivilege(SecurityContext, String, boolean)}
+ * controller. Only confidential clients are allowed to be super
+ * clients.
+ * 
  * @author margaretha
  *
  */
 @Controller
 @Path("oauth2/client")
+@ResourceFilters({ AuthenticationFilter.class, BlockingFilter.class })
 public class OAuthClientController {
 
     @Autowired
     private OAuth2ClientService clientService;
     @Autowired
+    private OAuth2ScopeService scopeService;
+    @Autowired
     private OAuth2ResponseHandler responseHandler;
 
     /**
@@ -70,13 +90,13 @@
     @Path("register")
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
-    @ResourceFilters({ AuthenticationFilter.class, BlockingFilter.class })
     public OAuth2ClientDto registerClient (
             @Context SecurityContext securityContext,
             OAuth2ClientJson clientJson) {
         TokenContext context =
                 (TokenContext) securityContext.getUserPrincipal();
         try {
+            scopeService.verifyScope(context, OAuth2Scope.REGISTER_CLIENT);
             return clientService.registerClient(clientJson,
                     context.getUsername());
         }
@@ -85,7 +105,6 @@
         }
     }
 
-
     /**
      * Deregisters a client requires client owner authentication. For
      * confidential clients, client authentication is also required.
@@ -101,7 +120,6 @@
     @DELETE
     @Path("deregister/{client_id}")
     @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
-    @ResourceFilters({ AuthenticationFilter.class, BlockingFilter.class })
     public Response deregisterPublicClient (
             @Context SecurityContext securityContext,
             @PathParam("client_id") String clientId,
@@ -109,6 +127,7 @@
         TokenContext context =
                 (TokenContext) securityContext.getUserPrincipal();
         try {
+            scopeService.verifyScope(context, OAuth2Scope.DEREGISTER_CLIENT);
             clientService.deregisterClient(clientId, clientSecret,
                     context.getUsername());
             return Response.ok().build();
@@ -132,7 +151,6 @@
     @Path("reset")
     @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
     @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
-    @ResourceFilters({ AuthenticationFilter.class, BlockingFilter.class })
     public OAuth2ClientDto resetClientSecret (
             @Context SecurityContext securityContext,
             @FormParam("client_id") String clientId,
@@ -140,6 +158,7 @@
         TokenContext context =
                 (TokenContext) securityContext.getUserPrincipal();
         try {
+            scopeService.verifyScope(context, OAuth2Scope.RESET_CLIENT_SECRET);
             return clientService.resetSecret(clientId, clientSecret,
                     context.getUsername());
         }
@@ -148,4 +167,51 @@
         }
     }
 
+    /**
+     * Facilitates editing client privileges for admin purposes, e.g.
+     * setting a specific client to be a super client, and vice versa.
+     * Only confidential clients are allowed to be super clients.
+     * 
+     * @param securityContext
+     * @param clientId
+     * @param super true indicating super client, false otherwise
+     * @return Response status OK, if successful 
+     */
+    @POST
+    @Path("privilege")
+    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+    public Response updateClientPrivilege (
+            @Context SecurityContext securityContext,
+            @FormParam("client_id") String clientId,
+            @FormParam("super") String isSuper) {
+        TokenContext context =
+                (TokenContext) securityContext.getUserPrincipal();
+        try {
+            scopeService.verifyScope(context, OAuth2Scope.ADMIN);
+            clientService.updatePrivilege(context.getUsername(), clientId,
+                    Boolean.valueOf(isSuper));
+            return Response.ok().build();
+        }
+        catch (KustvaktException e) {
+            throw responseHandler.throwit(e);
+        }
+    }
+
+    @GET
+    @Path("info/{client_id}")
+    @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
+    public OAuth2ClientInfoDto retrieveClientInfo (
+            @Context SecurityContext securityContext,
+            @PathParam("client_id") String clientId) {
+        TokenContext context =
+                (TokenContext) securityContext.getUserPrincipal();
+        try {
+            scopeService.verifyScope(context, OAuth2Scope.CLIENT_INFO);
+            return clientService.retrieveClientInfo(context.getUsername(),
+                    clientId);
+        }
+        catch (KustvaktException e) {
+            throw responseHandler.throwit(e);
+        }
+    }
 }