Skip to content

Provide better error message when API authentication fails #5683

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jul 23, 2024
9 changes: 4 additions & 5 deletions api/src/org/labkey/api/action/ApiResponseWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,10 @@ public abstract class ApiResponseWriter implements AutoCloseable
private static final String RESPONSE_FORMAT_ATTRIBUTE = ApiResponseWriter.class.getName() + "$responseFormat";

/*
* (MAB) This code defaults to using setting the response to SC_BAD_REQUEST
* when any error is encountered. I think this is wrong. Expected
* errors should be encoded in a normal JSON response and SC_OK.
* (MAB) This code defaults to setting the response to SC_BAD_REQUEST when any error is encountered. I think this
* is wrong. Expected errors should be encoded in a normal JSON response and SC_OK.
*
* Also, this using SC_BAD_REQUEST means failed APIs get taggd by BlockListFilter
* Also, this using SC_BAD_REQUEST means failed APIs get tagged by BlockListFilter
*
* Allow new code to specify that SC_OK should be used for errors
*/
Expand Down Expand Up @@ -341,7 +340,7 @@ protected void write(ApiResponse response) throws IOException

/**
* Even though the default exception handling is implemented here, we require that response.render()
* invokes this method in its own catch() block before endResponse(). This seems cleaner than coordinating
* invokes this method in its own catch() block before endResponse(). This seems cleaner than coordinating
* to have render() not output matching { open and close } braces.
*
* @see ApiResponse#render(ApiResponseWriter)
Expand Down
31 changes: 19 additions & 12 deletions api/src/org/labkey/api/action/SpringActionController.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,16 @@

package org.labkey.api.action;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.json.JSONObject;
import org.labkey.api.action.ApiResponseWriter.Format;
import org.labkey.api.admin.AdminUrls;
import org.labkey.api.collections.CaseInsensitiveHashMap;
import org.labkey.api.data.Container;
Expand Down Expand Up @@ -70,9 +75,6 @@
import org.springframework.web.servlet.mvc.Controller;
import org.springframework.web.servlet.view.RedirectView;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
Expand Down Expand Up @@ -378,6 +380,19 @@ private ModelAndView handleBadRequestException(HttpServletRequest request, HttpS
return null;
}

public static void setResponseFormat(@NotNull HttpServletRequest request, @Nullable Format defaultFormat)
{
Format responseFormat = Format.getFormatByName(request.getParameter(RESPONSE_FORMAT_PARAMETER_NAME), null);
if (responseFormat == null)
{
responseFormat = defaultFormat;
}
if (responseFormat != null)
{
ApiResponseWriter.setResponseFormat(request, responseFormat);
}
}

@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
{
Expand Down Expand Up @@ -407,15 +422,7 @@ public ModelAndView handleRequest(HttpServletRequest request, HttpServletRespons
if (!(controller instanceof PermissionCheckable checkable))
throw new IllegalStateException("All actions must implement PermissionCheckable. " + controller.getClass().getName() + " should extend PermissionCheckableAction or one of its subclasses.");

ApiResponseWriter.Format responseFormat = ApiResponseWriter.Format.getFormatByName(request.getParameter(RESPONSE_FORMAT_PARAMETER_NAME), null);
if (responseFormat == null)
{
responseFormat = checkable.getDefaultResponseFormat();
}
if (responseFormat != null)
{
ApiResponseWriter.setResponseFormat(request, responseFormat);
}
setResponseFormat(request, checkable.getDefaultResponseFormat());

ActionURL redirectURL = getUpgradeMaintenanceRedirect(request, controller);

Expand Down
24 changes: 15 additions & 9 deletions api/src/org/labkey/api/security/AuthFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@

package org.labkey.api.security;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.apache.commons.collections4.IteratorUtils;
import org.apache.commons.lang3.StringUtils;
import org.labkey.api.module.ModuleLoader;
Expand All @@ -31,18 +40,10 @@
import org.labkey.api.util.HttpUtil;
import org.labkey.api.util.HttpsUtil;
import org.labkey.api.util.Pair;
import org.labkey.api.view.UnauthorizedException;
import org.labkey.api.view.ViewServlet;
import org.labkey.api.view.template.PageConfig;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
Expand Down Expand Up @@ -187,6 +188,11 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, uee.getMessage());
return;
}
catch (UnauthorizedException ue)
{
ExceptionUtil.handleException(req, resp, ue, ue.getMessage(), false);
return;
}

if (null == user)
{
Expand Down
Loading