15

We secure our REST services (for server to server communication, no user involved) with Spring Security OAuth2. However when one tries to access a protected resource in a browser, it will show:

<oauth>
    <error_description>
        An Authentication object was not found in the SecurityContext
    </error_description>
    <error>unauthorized</error>
</oauth>

We want this to be a custom page of our own choosing. Is there a way?

Setting the access-denied-page won't do. For one it requires the definition of a login page which we don't have as this is a pure server to server communication. For another this attribute is supposedly deprecated since Spring 3.0.. or something.

Anyway.. Debugged my way into the OAuth Error Handling. And found that the response seems to somehow get enriched with the information I see on the error page. Apparently no page rendering at all is done so it looks like there is no error page to replace..?!

At least we want to hide the fact that we use OAuth and just display a basic "Denied" text if we can't have a "real" page.. So maybe I'll have to extend the spring security handler or add a custom filter to modify the response?!

Maybe a redirect to our error page?

Thanks!

Edit

For our current setup check my other SO question here

Community
  • 1
  • 1
Pete
  • 10,720
  • 25
  • 94
  • 139
  • I'm trying to do the same thing at the momment. Not sure how yet, if you got a solution, please share. I found this (link below) forum discussion, and it seems it has something to do with using handler of RestTemplate... http://forum.springsource.org/showthread.php?132846-Securing-REST-with-OAuth2-Authentication-object-was-not-found-in-the-SecurityContext – rafaelxy Mar 05 '13 at 13:46
  • I think I understood now, the OAuth server will not handle error and redirect, that is a responsibility of the client application trying to authenticate. Am I right? – rafaelxy Mar 05 '13 at 14:15
  • I don't now if this will work with OAuth but would not do this the job ? – Josef Prochazka Mar 22 '13 at 14:29
  • No that wont work.. Tried it.. Had to define a login page and more even though I dont need it but it will still just get ignored. I don't think it generates an actual 403 response – Pete Mar 25 '13 at 09:39

1 Answers1

15

I had to remove the oauth detail too and my solution was to implement my own OAuth2ExceptionRenderer

package org.some.nice.code;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.security.oauth2.provider.error.OAuth2ExceptionRenderer;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletWebRequest;

public class HeaderOnlyOAuth2ExceptionRenderer implements OAuth2ExceptionRenderer
{
    private final Log logger = LogFactory
            .getLog(MyOAuth2ExceptionRenderer.class);

    public void handleHttpEntityResponse(HttpEntity<?> responseEntity,
            ServletWebRequest webRequest) throws Exception
    {
        if (responseEntity == null)
        {
            return;
        }
        HttpInputMessage inputMessage = createHttpInputMessage(webRequest);
        HttpOutputMessage outputMessage = createHttpOutputMessage(webRequest);
        logger.info("filtering headers only...");
        if (responseEntity instanceof ResponseEntity
                && outputMessage instanceof ServerHttpResponse)
        {
            ((ServerHttpResponse) outputMessage)
                    .setStatusCode(((ResponseEntity<?>) responseEntity)
                            .getStatusCode());
        }
        HttpHeaders entityHeaders = responseEntity.getHeaders();
        if (!entityHeaders.isEmpty())
        {
            outputMessage.getHeaders().putAll(entityHeaders);
        }
    }

    private HttpInputMessage createHttpInputMessage(NativeWebRequest webRequest)
            throws Exception
    {
        HttpServletRequest servletRequest = webRequest
                .getNativeRequest(HttpServletRequest.class);
        return new ServletServerHttpRequest(servletRequest);
    }

    private HttpOutputMessage createHttpOutputMessage(
            NativeWebRequest webRequest) throws Exception
    {
        HttpServletResponse servletResponse = (HttpServletResponse) webRequest
                .getNativeResponse();
        return new ServletServerHttpResponse(servletResponse);
    }
}

Then you will have to reference it within your spring context

     <bean id="oauthAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
        <property name="realmName" value="theRealm" />
<property name="exceptionRenderer" ref="headerOnlyExceptionRender" />
    </bean>

    <bean id="clientAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
        <property name="realmName" value="theRealm/client" />
        <property name="typeName" value="Basic" />
<property name="exceptionRenderer" ref="headerOnlyExceptionRender" />
    </bean>



    <bean id="oauthAccessDeniedHandler" class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler">
<property name="exceptionRenderer" ref="headerOnlyExceptionRender" />
</bean>


    <bean id="headerOnlyExceptionRender" class="org.some.nice.code.HeaderOnlyOAuth2ExceptionRenderer"/>

Hope it helps.

Pascal Rodriguez
  • 981
  • 9
  • 12
  • Thanks! So it is as I thought.. will try out your solution asap – Pete Apr 08 '13 at 16:55
  • This only worked when the error was an OAuth2 client error. But I couldn't make it work if the error was wrong password error... I got crazy debugging spring classes and couldn't make it. – Fernando Fradegrada Feb 21 '19 at 18:21