Browse Source

improve rest service error messages

Jason Rivard 7 years ago
parent
commit
6384708ffe

+ 12 - 6
server/src/main/java/password/pwm/http/HttpMethod.java

@@ -23,17 +23,19 @@
 package password.pwm.http;
 
 public enum HttpMethod {
-    POST(false),
-    GET(true),
-    DELETE(false),
-    PUT(false),
-    PATCH(false),
+    POST(   false,  true),
+    GET(    true,   false),
+    DELETE( false,  true),
+    PUT(    false,  true),
+    PATCH(  false,  true),
 
     ;
 
     private final boolean idempotent;
+    private final boolean hasBody;
 
-    HttpMethod(final boolean idempotent) {
+    HttpMethod(final boolean idempotent, final boolean hasBody) {
+        this.hasBody = hasBody;
         this.idempotent = idempotent;
     }
 
@@ -49,4 +51,8 @@ public enum HttpMethod {
     public boolean isIdempotent() {
         return idempotent;
     }
+
+    public boolean isHasBody() {
+        return hasBody;
+    }
 }

+ 10 - 0
server/src/main/java/password/pwm/http/tag/PwmScriptRefTag.java

@@ -22,6 +22,7 @@
 
 package password.pwm.http.tag;
 
+import password.pwm.PwmConstants;
 import password.pwm.http.JspUtility;
 import password.pwm.http.PwmRequest;
 import password.pwm.http.tag.url.PwmUrlTag;
@@ -51,6 +52,7 @@ public class PwmScriptRefTag extends TagSupport {
             final String cspNonce = pwmRequest.getCspNonce();
 
             String url = getUrl();
+            url = convertUrl(url);
             url = PwmUrlTag.insertContext(pageContext,url);
             url = PwmUrlTag.insertResourceNonce(pwmRequest.getPwmApplication(), url);
 
@@ -62,4 +64,12 @@ public class PwmScriptRefTag extends TagSupport {
         return EVAL_PAGE;
     }
 
+    private String convertUrl(final String input) {
+        final String pwmClientUrl = "/resources/webjars/pwm-client/";
+        if (input.contains(pwmClientUrl)) {
+            final String correctedUrl = "/resources/webjars/" + PwmConstants.PWM_APP_NAME.toLowerCase() + "-client/";
+            return input.replace(pwmClientUrl, correctedUrl);
+        }
+        return input;
+    }
 }

+ 12 - 1
server/src/main/java/password/pwm/ws/server/RestRequest.java

@@ -81,7 +81,18 @@ public class RestRequest extends PwmHttpRequestWrapper {
     }
 
     public HttpContentType readAcceptType() {
-        return HttpContentType.fromContentTypeHeader(readHeaderValueAsString(HttpHeader.Accept));
+
+        return readAcceptType(getHttpServletRequest());
+    }
+
+    static HttpContentType readAcceptType(final HttpServletRequest request) {
+        final String acceptHeaderValue = request.getHeader(HttpHeader.Accept.getHttpName());
+        final boolean anyValue = "*".equals(acceptHeaderValue)
+                || "*/*".equals(acceptHeaderValue);
+        return anyValue
+                ? HttpContentType.json
+                : HttpContentType.fromContentTypeHeader(acceptHeaderValue);
+
     }
 
     public Locale getLocale() {

+ 24 - 8
server/src/main/java/password/pwm/ws/server/RestServlet.java

@@ -105,7 +105,7 @@ public abstract class RestServlet extends HttpServlet{
 
             final RestRequest restRequest = RestRequest.forRequest(pwmApplication, restAuthentication, sessionLabel, req);
 
-            checkRestServiceClassPermissions(restRequest);
+            preCheck(restRequest);
 
             preCheckRequest(restRequest);
 
@@ -157,6 +157,8 @@ public abstract class RestServlet extends HttpServlet{
         final HttpContentType reqContent = restRequest.readContentType();
         final HttpContentType reqAccept = restRequest.readAcceptType();
 
+        final boolean careAboutContentType = reqMethod.isHasBody();
+
         final MethodMatcher anyMatch = new MethodMatcher();
 
         final Collection<Method> methods = JavaHelper.getAllMethodsForClass(clazz);
@@ -170,7 +172,7 @@ public abstract class RestServlet extends HttpServlet{
                     anyMatch.setMethodMatch(true);
                 }
 
-                if (annotation.consumes().length == 0 || Arrays.asList(annotation.consumes()).contains(reqContent)) {
+                if (!careAboutContentType || annotation.consumes().length == 0 || Arrays.asList(annotation.consumes()).contains(reqContent)) {
                     loopMatch.setContentMatch(true);
                     anyMatch.setContentMatch(true);
                 }
@@ -204,7 +206,7 @@ public abstract class RestServlet extends HttpServlet{
         throw PwmUnrecoverableException.newException(PwmError.ERROR_REST_INVOCATION_ERROR, errorMsg);
     }
 
-    private void checkRestServiceClassPermissions(final RestRequest restRequest)
+    private void preCheck(final RestRequest restRequest)
             throws PwmUnrecoverableException
     {
         final RestWebServer classAnnotation = this.getClass().getDeclaredAnnotation(RestWebServer.class);
@@ -216,8 +218,17 @@ public abstract class RestServlet extends HttpServlet{
             throw PwmUnrecoverableException.newException(PwmError.ERROR_UNAUTHORIZED, "access to " + classAnnotation.webService() + " service is not permitted for this login");
         }
 
-        if (restRequest.getRestAuthentication().getType() == RestAuthenticationType.PUBLIC) {
-            throw PwmUnrecoverableException.newException(PwmError.ERROR_UNAUTHORIZED, "this service requires authentication");
+        if (classAnnotation.requireAuthentication()) {
+            if (restRequest.getRestAuthentication().getType() == RestAuthenticationType.PUBLIC) {
+                throw PwmUnrecoverableException.newException(PwmError.ERROR_UNAUTHORIZED, "this service requires authentication");
+            }
+        }
+
+        if (restRequest.getMethod().isHasBody()) {
+            if (restRequest.readContentType() == null) {
+                final String message = restRequest.getMethod() + " method requires " + HttpHeader.Content_Type.getHttpName() + " header";
+                throw PwmUnrecoverableException.newException(PwmError.ERROR_UNAUTHORIZED, message);
+            }
         }
     }
 
@@ -230,7 +241,7 @@ public abstract class RestServlet extends HttpServlet{
     )
             throws IOException
     {
-        final HttpContentType acceptType = HttpContentType.fromContentTypeHeader(request.getHeader(HttpHeader.Accept.getHttpName()));
+        final HttpContentType acceptType = RestRequest.readAcceptType(request);
         resp.setHeader(HttpHeader.Server.getHttpName(), PwmConstants.PWM_APP_NAME);
 
         if (acceptType != null) {
@@ -258,12 +269,17 @@ public abstract class RestServlet extends HttpServlet{
                 break;
 
                 default: {
-                    final String msg = "unhandled " + HttpHeader.Content_Type.getHttpName() + " header value in request";
+                    final String msg = "unhandled " + HttpHeader.Accept.getHttpName() + " header value in request";
                     outputLastHopeError(msg, resp);
                 }
             }
         } else {
-            final String msg = "unknown " + HttpHeader.Content_Type.getHttpName() + " header value in request";
+            final String msg;
+            if (StringUtil.isEmpty(request.getHeader(HttpHeader.Accept.getHttpName()))) {
+                msg = "missing " + HttpHeader.Accept.getHttpName() + " header value in request";
+            } else {
+                msg = "unknown value for " + HttpHeader.Accept.getHttpName() + " header value in request";
+            }
             outputLastHopeError(msg, resp);
         }
     }

+ 2 - 1
server/src/main/java/password/pwm/ws/server/rest/RestVerifyResponsesServer.java

@@ -33,6 +33,7 @@ import password.pwm.config.option.WebServiceUsage;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.http.HttpContentType;
 import password.pwm.http.HttpMethod;
+import password.pwm.i18n.Message;
 import password.pwm.util.java.JsonUtil;
 import password.pwm.util.java.TimeDuration;
 import password.pwm.util.logging.PwmLogger;
@@ -108,7 +109,7 @@ public class RestVerifyResponsesServer extends RestServlet {
 
             final boolean verified = responseSet.test(jsonInput.toCrMap());
 
-            final RestResultBean restResultBean = RestResultBean.withData(verified);
+            final RestResultBean restResultBean = RestResultBean.forSuccessMessage(verified, restRequest, Message.Success_Unknown);
 
             LOGGER.debug(restRequest.getSessionLabel(), "completed /verifyresponses REST service in "
                     + TimeDuration.fromCurrent(startTime).asCompactString()