/** * Copyright 2005-2014 Restlet * * The contents of this file are subject to the terms of one of the following * open source licenses: Apache 2.0 or or EPL 1.0 (the "Licenses"). You can * select the license that you prefer but you may not use this file except in * compliance with one of these Licenses. * * You can obtain a copy of the Apache 2.0 license at * http://www.opensource.org/licenses/apache-2.0 * * You can obtain a copy of the EPL 1.0 license at * http://www.opensource.org/licenses/eclipse-1.0 * * See the Licenses for the specific language governing permissions and * limitations under the Licenses. * * Alternatively, you can obtain a royalty free commercial license with less * limitations, transferable or non-transferable, directly at * http://restlet.com/products/restlet-framework * * Restlet is a registered trademark of Restlet S.A.S. */ package org.restlet.ext.apispark.internal.agent.module; import java.util.List; import java.util.logging.Logger; import org.restlet.Context; import org.restlet.Request; import org.restlet.Response; import org.restlet.Restlet; import org.restlet.data.Status; import org.restlet.ext.apispark.internal.ApiSparkConfig; import org.restlet.ext.apispark.internal.agent.AgentConfigurationException; import org.restlet.ext.apispark.internal.agent.AgentUtils; import org.restlet.ext.apispark.internal.agent.bean.ModulesSettings; import org.restlet.ext.apispark.internal.agent.bean.OperationAuthorization; import org.restlet.ext.apispark.internal.agent.resource.AuthorizationOperationsResource; import org.restlet.routing.Filter; import org.restlet.routing.Router; import org.restlet.routing.TemplateRoute; import org.restlet.security.Role; /** * Authorization module for the agent. * * @author Manuel Boillod */ public class AuthorizationModule extends Filter { /** * Wrap an {@link OperationAuthorization} in a {@link Restlet} class for * reuse of {@link Router#getNext(org.restlet.Request, org.restlet.Response)} logic. */ private static class RestletOperationAuthorization extends Restlet { private OperationAuthorization operationAuthorization; private RestletOperationAuthorization( OperationAuthorization operationAuthorization) { this.operationAuthorization = operationAuthorization; } public OperationAuthorization getOperationAuthorization() { return operationAuthorization; } @SuppressWarnings("unused") public void setOperationAuthorization( OperationAuthorization operationAuthorization) { this.operationAuthorization = operationAuthorization; } } /** Internal logger. */ protected static Logger LOGGER = Logger.getLogger(AuthorizationModule.class .getName()); public static final String MODULE_PATH = "/authorization"; public static final String OPERATIONS_AUTHORIZATIONS_PATH = MODULE_PATH + "/operations"; /** * Router is used for finding the Operation corresponding to a incoming * request. */ private Router router; /** * Create a new Authorization module with the specified settings. * * @param apiSparkConfig * The agent configuration. * @param modulesSettings * The modules settings. */ public AuthorizationModule(ApiSparkConfig apiSparkConfig, ModulesSettings modulesSettings) { this(apiSparkConfig, modulesSettings, null); } /** * Create a new Authorization module with the specified settings. * * @param apiSparkConfig * The agent configuration. * @param modulesSettings * The modules settings. * @param context * The context */ public AuthorizationModule(ApiSparkConfig apiSparkConfig, ModulesSettings modulesSettings, Context context) { super(context); AuthorizationOperationsResource authorizationOperationsClientResource = AgentUtils .getClientResource(apiSparkConfig, modulesSettings, AuthorizationOperationsResource.class, OPERATIONS_AUTHORIZATIONS_PATH); List<OperationAuthorization> operationAuthorizations; try { operationAuthorizations = authorizationOperationsClientResource .getAuthorizations(); } catch (Exception e) { throw new AgentConfigurationException( "Could not get authorization module configuration from APISpark connector service", e); } // Initialize the router router = new Router(); for (OperationAuthorization operationAuthorization : operationAuthorizations) { router.attach(operationAuthorization.getPathTemplate(), new RestletOperationAuthorization(operationAuthorization)); } } /** * Find the best {@link OperationAuthorization} for the incoming request and * check user authorization. * * @param request * The request to handle. * @param response * The response to update. * @return {@link org.restlet.routing.Filter#CONTINUE} if the user is * authorized. */ @Override protected int beforeHandle(Request request, Response response) { // find the corresponding Operation TemplateRoute templateRoute = (TemplateRoute) router.getNext(request, response); // check route exists if (templateRoute == null) { response.setStatus(Status.CLIENT_ERROR_NOT_FOUND); return STOP; } RestletOperationAuthorization restletOperationAuthorization = (RestletOperationAuthorization) templateRoute .getNext(); List<Role> userRoles = request.getClientInfo().getRoles(); // check that user has at least one authorized role (named group in // apispark) boolean authorized = false; OperationAuthorization operationAuthorization = restletOperationAuthorization .getOperationAuthorization(); List<String> groupsAllowed = operationAuthorization.getGroupsAllowed(); if (groupsAllowed == null) { LOGGER.warning("No group is allowed for method " + operationAuthorization.getMethod() + " on this resource: " + operationAuthorization.getPathTemplate()); } else { for (String groupAllowed : groupsAllowed) { if (hasRole(userRoles, groupAllowed) || "anyone".equals(groupAllowed)) { authorized = true; break; } } } if (authorized) { return CONTINUE; } else { response.setStatus(Status.CLIENT_ERROR_FORBIDDEN); return STOP; } } /** * Indicates if the given role is in the list of roles. * * @param roles * The list of roles. * @param roleName * The name of the role to look for. * @return True if the list of roles contains the given role. */ protected boolean hasRole(List<Role> roles, String roleName) { for (Role role : roles) { if (role.getName().equals(roleName)) { return true; } } return false; } }