This is an automated email from the ASF dual-hosted git repository.
grv pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/ofbiz-plugins.git The following commit(s) were added to refs/heads/trunk by this push: new 1361c3c Improved: Updated code to bypass auth for services having auth=false 2. Implemented ServiceValidationFilter to return various HTTP responses based on request's context(OFBIZ-11328) 1361c3c is described below commit 1361c3cdaf7d6756cc9abdc6c37450ef3d46f921 Author: Girish Vasmatkar <[hidden email]> AuthorDate: Sat Sep 26 14:30:47 2020 +0530 Improved: Updated code to bypass auth for services having auth=false 2. Implemented ServiceValidationFilter to return various HTTP responses based on request's context(OFBIZ-11328) --- .../org/apache/ofbiz/ws/rs/ConflictException.java | 38 +++++++++ .../apache/ofbiz/ws/rs/ServiceRequestFilter.java | 97 ++++++++++++++++++++++ .../ws/rs/annotation/ServiceRequestValidator.java | 33 ++++++++ .../apache/ofbiz/ws/rs/core/OFBizApiConfig.java | 2 + .../ws/rs/resources/OFBizServiceResource.java | 6 +- .../ofbiz/ws/rs/security/auth/APIAuthFilter.java | 29 +++++++ .../org/apache/ofbiz/ws/rs/util/RestApiUtil.java | 19 +++++ 7 files changed, 223 insertions(+), 1 deletion(-) diff --git a/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/ConflictException.java b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/ConflictException.java new file mode 100644 index 0000000..4d3c6f7 --- /dev/null +++ b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/ConflictException.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + *******************************************************************************/ +package org.apache.ofbiz.ws.rs; + +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Response; + +/** + * A HTTP 409 (Conflict) exception + */ +public class ConflictException extends WebApplicationException { + + private static final long serialVersionUID = -3002310435429546325L; + + /** + * Construct a new ConflictException exception. + */ + public ConflictException(String message) { + super(message, Response.Status.CONFLICT); + } + +} diff --git a/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/ServiceRequestFilter.java b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/ServiceRequestFilter.java new file mode 100644 index 0000000..9021edf --- /dev/null +++ b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/ServiceRequestFilter.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + *******************************************************************************/ +package org.apache.ofbiz.ws.rs; + +import java.io.IOException; + +import javax.annotation.Priority; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.NotFoundException; +import javax.ws.rs.Priorities; +import javax.ws.rs.container.ContainerRequestContext; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.ResourceInfo; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.UriInfo; +import javax.ws.rs.ext.Provider; + +import org.apache.ofbiz.base.util.Debug; +import org.apache.ofbiz.base.util.UtilValidate; +import org.apache.ofbiz.service.GenericServiceException; +import org.apache.ofbiz.service.ModelService; +import org.apache.ofbiz.webapp.WebAppUtil; +import org.apache.ofbiz.ws.rs.annotation.ServiceRequestValidator; +import org.apache.ofbiz.ws.rs.util.RestApiUtil; + +@Provider +@ServiceRequestValidator +@Priority(Priorities.USER) +public class ServiceRequestFilter implements ContainerRequestFilter { + + private static final String MODULE = ServiceRequestFilter.class.getName(); + + @Context + private UriInfo uriInfo; + + @Context + private ResourceInfo resourceInfo; + + @Context + private HttpServletRequest httpRequest; + + @Context + private ServletContext servletContext; + + /** + * @param requestContext + * @throws IOException + */ + @Override + public void filter(ContainerRequestContext requestContext) throws IOException { + Debug.logInfo("Service request is going to get validated!", MODULE); + String service = (String) RestApiUtil.extractParams(uriInfo.getPathParameters()).get("serviceName"); + String method = requestContext.getMethod(); + if (UtilValidate.isNotEmpty(service)) { + ModelService mdService = null; + try { + mdService = WebAppUtil.getDispatcher(servletContext).getDispatchContext().getModelService(service); + } catch (GenericServiceException e) { + Debug.logError(e.getMessage(), MODULE); + } + + if (mdService == null) { + throw new NotFoundException("Service '" + service + "' not found."); + } + + if (mdService != null && !mdService.isExport()) { + throw new NotFoundException("Service '" + service + "' is not exportable."); + } + + if (mdService != null && UtilValidate.isEmpty(mdService.getAction())) { + throw new ConflictException("Service '" + service + "' does not have HTTP action defined."); + } + + if (!mdService.getAction().equalsIgnoreCase(method)) { + throw new MethodNotAllowedException("HTTP " + method + " is not allowed on service '" + service + "'"); + } + } + } + +} diff --git a/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/annotation/ServiceRequestValidator.java b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/annotation/ServiceRequestValidator.java new file mode 100644 index 0000000..61a4655 --- /dev/null +++ b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/annotation/ServiceRequestValidator.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + *******************************************************************************/ +package org.apache.ofbiz.ws.rs.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.ws.rs.NameBinding; + +@NameBinding +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.TYPE }) +public @interface ServiceRequestValidator { + +} diff --git a/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/core/OFBizApiConfig.java b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/core/OFBizApiConfig.java index 5eecd73..4e16d3f 100644 --- a/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/core/OFBizApiConfig.java +++ b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/core/OFBizApiConfig.java @@ -33,6 +33,7 @@ import org.apache.ofbiz.base.component.ComponentConfig; import org.apache.ofbiz.base.component.ComponentException; import org.apache.ofbiz.base.util.Debug; import org.apache.ofbiz.base.util.UtilValidate; +import org.apache.ofbiz.ws.rs.ServiceRequestFilter; import org.apache.ofbiz.ws.rs.model.ModelApi; import org.apache.ofbiz.ws.rs.model.ModelApiReader; import org.apache.ofbiz.ws.rs.model.ModelOperation; @@ -57,6 +58,7 @@ public class OFBizApiConfig extends ResourceConfig { // packages("io.swagger.v3.jaxrs2.integration.resources"); //commenting it out // to generate customized OpenApi Spec register(JacksonFeature.class); + register(ServiceRequestFilter.class); register(MultiPartFeature.class); if (Debug.verboseOn()) { register(new LoggingFeature(Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME), Level.INFO, diff --git a/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/resources/OFBizServiceResource.java b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/resources/OFBizServiceResource.java index 6b335b6..61cb6af 100644 --- a/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/resources/OFBizServiceResource.java +++ b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/resources/OFBizServiceResource.java @@ -54,14 +54,18 @@ import org.apache.ofbiz.service.LocalDispatcher; import org.apache.ofbiz.service.ModelService; import org.apache.ofbiz.ws.rs.ApiServiceRequest; import org.apache.ofbiz.ws.rs.ServiceRequestProcessor; +import org.apache.ofbiz.ws.rs.annotation.ServiceRequestValidator; import org.apache.ofbiz.ws.rs.response.Success; import org.apache.ofbiz.ws.rs.security.Secured; @Secured -@Path("/services") +@Path(OFBizServiceResource.BASE_PATH) @Provider +@ServiceRequestValidator public class OFBizServiceResource extends OFBizResource { + public static final String BASE_PATH = "/services"; + @Context private UriInfo uriInfo; diff --git a/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/security/auth/APIAuthFilter.java b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/security/auth/APIAuthFilter.java index a77f955..3834464 100644 --- a/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/security/auth/APIAuthFilter.java +++ b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/security/auth/APIAuthFilter.java @@ -21,14 +21,17 @@ package org.apache.ofbiz.ws.rs.security.auth; import java.io.IOException; import java.util.Map; +import javax.annotation.Priority; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Priorities; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.ResourceInfo; import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; import javax.ws.rs.ext.Provider; import org.apache.ofbiz.base.util.Debug; @@ -37,9 +40,12 @@ import org.apache.ofbiz.entity.Delegator; import org.apache.ofbiz.entity.GenericEntityException; import org.apache.ofbiz.entity.GenericValue; import org.apache.ofbiz.entity.util.EntityQuery; +import org.apache.ofbiz.service.GenericServiceException; import org.apache.ofbiz.service.ModelService; +import org.apache.ofbiz.webapp.WebAppUtil; import org.apache.ofbiz.webapp.control.JWTManager; import org.apache.ofbiz.ws.rs.common.AuthenticationScheme; +import org.apache.ofbiz.ws.rs.resources.OFBizServiceResource; import org.apache.ofbiz.ws.rs.security.Secured; import org.apache.ofbiz.ws.rs.util.RestApiUtil; @@ -48,11 +54,15 @@ import org.apache.ofbiz.ws.rs.util.RestApiUtil; */ @Secured @Provider +@Priority(Priorities.AUTHORIZATION) public class APIAuthFilter implements ContainerRequestFilter { private static final String MODULE = APIAuthFilter.class.getName(); @Context + private UriInfo uriInfo; + + @Context private ResourceInfo resourceInfo; @Context @@ -65,6 +75,21 @@ public class APIAuthFilter implements ContainerRequestFilter { */ @Override public void filter(ContainerRequestContext requestContext) throws IOException { + if (isServiceResource()) { + String service = (String) RestApiUtil.extractParams(uriInfo.getPathParameters()).get("serviceName"); + if (UtilValidate.isNotEmpty(service)) { + ModelService mdService = null; + try { + mdService = WebAppUtil.getDispatcher(servletContext).getDispatchContext().getModelService(service); + } catch (GenericServiceException e) { + Debug.logError(e.getMessage(), MODULE); + } + // Skip auth for services auth=false in service definition + if (mdService != null && !mdService.isAuth()) { + return; + } + } + } String authorizationHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION); Delegator delegator = (Delegator) servletContext.getAttribute("delegator"); if (!isTokenBasedAuthentication(authorizationHeader)) { @@ -124,4 +149,8 @@ public class APIAuthFilter implements ContainerRequestFilter { return userLogin; } + private boolean isServiceResource() { + return OFBizServiceResource.class.isAssignableFrom(resourceInfo.getResourceClass()); + } + } diff --git a/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/util/RestApiUtil.java b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/util/RestApiUtil.java index 309ca53..2cbde9d 100644 --- a/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/util/RestApiUtil.java +++ b/ofbiz-rest-impl/src/main/java/org/apache/ofbiz/ws/rs/util/RestApiUtil.java @@ -18,10 +18,15 @@ *******************************************************************************/ package org.apache.ofbiz.ws.rs.util; +import java.util.HashMap; +import java.util.Map; + import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; +import org.apache.ofbiz.base.util.UtilValidate; import org.apache.ofbiz.ws.rs.response.Error; import org.apache.ofbiz.ws.rs.response.Success; @@ -49,4 +54,18 @@ public final class RestApiUtil { Error error = new Error(statusCode, reasonPhrase, message); return Response.status(statusCode).type(MediaType.APPLICATION_JSON).entity(error); } + + /** + * @param multivaluedMap + * @return + */ + public static Map<String, Object> extractParams(MultivaluedMap<String, String> multivaluedMap) { + Map<String, Object> result = new HashMap<>(); + multivaluedMap.forEach((name, values) -> { + if (UtilValidate.isNotEmpty(values)) { + result.put(name, (values.size() != 1) ? values : values.get(0)); + } + }); + return result; + } } |
Free forum by Nabble | Edit this page |