/*
* oxAuth is available under the MIT License (2008). See http://opensource.org/licenses/MIT for full text.
*
* Copyright (c) 2014, Gluu
*/
package org.xdi.oxauth.uma.ws.rs;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import org.gluu.site.ldap.persistence.LdapEntryManager;
import org.slf4j.Logger;
import org.xdi.oxauth.model.common.AuthorizationGrant;
import org.xdi.oxauth.model.common.uma.UmaRPT;
import org.xdi.oxauth.model.error.ErrorResponseFactory;
import org.xdi.oxauth.model.uma.RptAuthorizationRequest;
import org.xdi.oxauth.model.uma.RptAuthorizationResponse;
import org.xdi.oxauth.model.uma.UmaConstants;
import org.xdi.oxauth.model.uma.UmaErrorResponseType;
import org.xdi.oxauth.model.uma.persistence.ResourceSetPermission;
import org.xdi.oxauth.model.util.Util;
import org.xdi.oxauth.service.ClientService;
import org.xdi.oxauth.service.uma.ResourceSetPermissionManager;
import org.xdi.oxauth.service.uma.RptManager;
import org.xdi.oxauth.service.uma.UmaValidationService;
import org.xdi.oxauth.service.uma.authorization.AuthorizationService;
import org.xdi.oxauth.util.ServerUtil;
import com.wordnik.swagger.annotations.Api;
/**
* The endpoint at which the requester asks for authorization to have a new permission.
*/
@Path("/requester/perm")
@Api(value = "/requester/perm", description = "RPT authorization endpoint. RPT is authorized with new permission(s).")
public class RptPermissionAuthorizationWS {
@Inject
private Logger log;
@Inject
private ErrorResponseFactory errorResponseFactory;
@Inject
private RptManager rptManager;
@Inject
private ResourceSetPermissionManager resourceSetPermissionManager;
@Inject
private UmaValidationService umaValidationService;
@Inject
private AuthorizationService umaAuthorizationService;
@Inject
private ClientService clientService;
@Inject
private LdapEntryManager ldapEntryManager;
@POST
@Consumes({UmaConstants.JSON_MEDIA_TYPE})
@Produces({UmaConstants.JSON_MEDIA_TYPE})
public Response requestRptPermissionAuthorization(
@HeaderParam("Authorization") String authorization,
@HeaderParam("Host") String amHost,
RptAuthorizationRequest rptAuthorizationRequest,
@Context HttpServletRequest httpRequest) {
try {
final AuthorizationGrant grant = umaValidationService.assertHasAuthorizationScope(authorization);
final String validatedAmHost = umaValidationService.validateAmHost(amHost);
final UmaRPT rpt = authorizeRptPermission(authorization, rptAuthorizationRequest, httpRequest, grant, validatedAmHost);
// convert manually to avoid possible conflict between resteasy providers, e.g. jettison, jackson
return Response.ok(ServerUtil.asJson(new RptAuthorizationResponse(rpt.getCode()))).build();
} catch (Exception ex) {
log.error("Exception happened", ex);
if (ex instanceof WebApplicationException) {
throw (WebApplicationException) ex;
}
throw new WebApplicationException(Response.status(Response.Status.INTERNAL_SERVER_ERROR)
.entity(errorResponseFactory.getUmaJsonErrorResponse(UmaErrorResponseType.SERVER_ERROR)).build());
}
}
private UmaRPT authorizeRptPermission(String authorization,
RptAuthorizationRequest rptAuthorizationRequest,
HttpServletRequest httpRequest,
AuthorizationGrant grant,
String amHost) {
UmaRPT rpt;
if (Util.isNullOrEmpty(rptAuthorizationRequest.getRpt())) {
rpt = rptManager.createRPT(authorization, amHost, false);
} else {
rpt = rptManager.getRPTByCode(rptAuthorizationRequest.getRpt());
}
// Validate RPT
try {
umaValidationService.validateRPT(rpt);
} catch (WebApplicationException e) {
// according to latest UMA spec ( dated 2015-02-23 https://docs.kantarainitiative.org/uma/draft-uma-core.html)
// it's up to implementation whether to create new RPT for each request or pass back requests RPT.
// Here we decided to pass back new RPT if request's RPT in invalid.
rpt = rptManager.getRPTByCode(rptAuthorizationRequest.getRpt());
}
final ResourceSetPermission resourceSetPermission = resourceSetPermissionManager.getResourceSetPermissionByTicket(rptAuthorizationRequest.getTicket());
// Validate resource set permission
umaValidationService.validateResourceSetPermission(resourceSetPermission);
// Add permission to RPT
if (umaAuthorizationService.allowToAddPermission(grant, rpt, resourceSetPermission, httpRequest, rptAuthorizationRequest.getClaims())) {
rptManager.addPermissionToRPT(rpt, resourceSetPermission);
invalidateTicket(resourceSetPermission);
return rpt;
}
// throw not authorized exception
throw new WebApplicationException(Response.status(Response.Status.FORBIDDEN)
.entity(errorResponseFactory.getUmaJsonErrorResponse(UmaErrorResponseType.NOT_AUTHORIZED_PERMISSION)).build());
}
private void invalidateTicket(ResourceSetPermission resourceSetPermission) {
try {
resourceSetPermission.setAmHost("invalidated"); // invalidate ticket and persist
ldapEntryManager.merge(resourceSetPermission);
} catch (Exception e) {
log.error("Failed to invalidate ticket: " + resourceSetPermission.getTicket() + ". " + e.getMessage(), e);
}
}
}