blob: ae27c809b08537f30c1223d3f9a8c6f081ccaf1a [file] [log] [blame]
package de.ids_mannheim.korap.web.controller;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
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 de.ids_mannheim.korap.constant.OAuth2Scope;
import de.ids_mannheim.korap.exceptions.KustvaktException;
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.APIVersionFilter;
import de.ids_mannheim.korap.web.filter.AuthenticationFilter;
import de.ids_mannheim.korap.web.filter.BlockingFilter;
import de.ids_mannheim.korap.web.input.OAuth2ClientJson;
import de.ids_mannheim.korap.web.utils.ResourceFilters;
/**
* 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("{version}/oauth2/client")
@ResourceFilters({ APIVersionFilter.class, AuthenticationFilter.class,
BlockingFilter.class })
@Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
public class OAuthClientController {
@Autowired
private OAuth2ClientService clientService;
@Autowired
private OAuth2ScopeService scopeService;
@Autowired
private OAuth2ResponseHandler responseHandler;
/**
* Registers a client application. Before starting an OAuth
* process, client applications have to be registered first. Only
* registered users are allowed to register client applications.
*
* After registration, the client receives a client_id and a
* client_secret, if the client is confidential (capable of
* storing the client_secret), that are needed in the
* authorization process.
*
* From RFC 6749:
* The authorization server SHOULD document the size of any
* identifier it issues.
*
* @param context
* @param clientJson
* a JSON object describing the client
* @return client_id and client_secret if the client type is
* confidential
*
* @see OAuth2ClientJson
*/
@POST
@Path("register")
@Consumes(MediaType.APPLICATION_JSON)
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());
}
catch (KustvaktException e) {
throw responseHandler.throwit(e);
}
}
/**
* Deregisters a client requires client owner authentication.
*
*
* @param securityContext
* @param clientId
* the client id
* @return HTTP Response OK if successful.
*/
@DELETE
@Path("deregister/{client_id}")
public Response deregisterClient (
@Context SecurityContext securityContext,
@PathParam("client_id") String clientId) {
TokenContext context =
(TokenContext) securityContext.getUserPrincipal();
try {
scopeService.verifyScope(context, OAuth2Scope.DEREGISTER_CLIENT);
clientService.deregisterClient(clientId, context.getUsername());
return Response.ok().build();
}
catch (KustvaktException e) {
throw responseHandler.throwit(e);
}
}
/**
* Resets client secret of the given client. This controller
* requires client owner and client authentication. Only
* confidential clients are issued client secrets.
*
* @param securityContext
* @param clientId
* @param clientSecret
* @return a new client secret
*/
@POST
@Path("reset")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public OAuth2ClientDto resetClientSecret (
@Context SecurityContext securityContext,
@FormParam("client_id") String clientId) {
TokenContext context =
(TokenContext) securityContext.getUserPrincipal();
try {
scopeService.verifyScope(context, OAuth2Scope.RESET_CLIENT_SECRET);
return clientService.resetSecret(clientId, context.getUsername());
}
catch (KustvaktException e) {
throw responseHandler.throwit(e);
}
}
@POST
@Path("{client_id}")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@ResourceFilters({ APIVersionFilter.class})
public OAuth2ClientInfoDto retrieveClientInfo (
@PathParam("client_id") String clientId,
@FormParam("super_client_id") String superClientId,
@FormParam("super_client_secret") String superClientSecret) {
try {
clientService.verifySuperClient(superClientId, superClientSecret);
return clientService.retrieveClientInfo(clientId);
}
catch (KustvaktException e) {
throw responseHandler.throwit(e);
}
}
/**
* Lists user clients having active refresh tokens (not revoked,
* not expired), except super clients.
*
* This service is not part of the OAuth2 specification. It is
* intended to facilitate users revoking any suspicious and
* misused access or refresh tokens.
*
* Only super clients are allowed to use this service. It requires
* user and client authentications.
*
* @param context
* @param superClientId
* the client id of the super client
* @param superClientSecret
* the client secret of the super client
* @return a list of clients having refresh tokens of the
* given user
*/
@POST
@Path("/list")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public List<OAuth2ClientInfoDto> listUserClients (
@Context SecurityContext context,
@FormParam("super_client_id") String superClientId,
@FormParam("super_client_secret") String superClientSecret,
@FormParam("authorized_only") boolean authorizedOnly) {
TokenContext tokenContext = (TokenContext) context.getUserPrincipal();
String username = tokenContext.getUsername();
try {
scopeService.verifyScope(tokenContext,
OAuth2Scope.LIST_USER_CLIENT);
clientService.verifySuperClient(superClientId, superClientSecret);
if (authorizedOnly) {
return clientService.listUserAuthorizedClients(username);
}
else {
return clientService.listUserRegisteredClients(username);
}
}
catch (KustvaktException e) {
throw responseHandler.throwit(e);
}
}
}