[ofbiz-plugins] branch trunk updated: 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)

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[ofbiz-plugins] branch trunk updated: 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)

grv-2
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;
+    }
 }