How do I change the content of a 401 response to a separate format?

I have a JAX-RS application on WildFly 10 that needs to be provided with a simple Basic Auth.

It works so far, but if authentication fails, the server responds

<html>
  <head>
    <title>Error</title>
  </head>
  <body>Unauthorized</body>
</html>

      

which is not my desired answer. I would prefer a custom answer (json).

How to do it?

What I have done so far:

  • I set up a new Wildfly security domain in my server config using a simple UserRolesLoginModule (which is enough in my case):

    <security-domain name="MySecurityDomain" cache-type="default">
      <authentication>
        <login-module code="org.jboss.security.auth.spi.UsersRolesLoginModule" flag="required">
          <module-option name="usersProperties" value="${jboss.server.config.dir}/users.properties"/>
          <module-option name="rolesProperties" value="${jboss.server.config.dir}/roles.properties"/>                            
          <module-option name="hashAlgorithm" value="MD5"/>
          <module-option name="hashEncoding" value="base64"/>
          <module-option name="hashCharset" value="UTF-8"/>
          <module-option name="unauthenticatedIdentity" value="UnauthenticatedAccess"/> 
        </login-module>                                       
      </authentication>
    </security-domain>
    
          

  • I have annotated all the services in the application:

         @SecurityDomain("MySecurityDomain")
         @RolesAllowed({ "RoleFromPropertyFile", "AnotherRoleFromPropertyFile" })
    
          

  • I created jboss-web.xml with content

        <jboss-web>
          <security-domain>MySecurityDomain</security-domain>
        </jboss-web>
    
          

  • I have a web.xml where I have tried many different things with no success ... :-( Current content:

        <security-constraint>
          <display-name>Deny all HTTP methods except GET and POST</display-name>
          <web-resource-collection>
            <web-resource-name>NextTest</web-resource-name>
            <url-pattern>/mypattern/*</url-pattern>
            <http-method-omission>GET</http-method-omission>
            <http-method-omission>POST</http-method-omission>
         </web-resource-collection>    
       </security-constraint>
       <login-config>
         <auth-method>BASIC</auth-method>
         <realm-name>MySecurityRealm</realm-name>
       </login-config>
      <security-role>
         <description>Access to all application parts</description>
         <role-name>all</role-name>
     </security-role>    
     <!-- and some more roles -->
    
          

  • I also implemented ExceptionMapper<EJBAccessException>

    to generate my own response. But this handler is only reached when I delete all content web.xml

    .

My guess is that the seizure is doing the authorization and handling the tamper response. If I remove the security configuration in web.xml

, the EJBs are available, but without evaluating the BasicAuth header. In this case, all requests are rejected.

I could avoid writing a servlet and use ExceptionMapper instead.

Any ideas what I missed?

+3


source to share


2 answers


I've experimented a bit with some code, and while it's not pretty, you can try something like:

import java.io.IOException;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.ext.Provider;

@Provider
public class AuthBodyResponseFilter implements ContainerResponseFilter {

    @Override
    public void filter(ContainerRequestContext requestContext,
                       ContainerResponseContext responseContext) throws IOException {

        if((responseContext.getStatus() == 401) && 
           (responseContext.getEntity() instanceof String))
            responseContext.setEntity("no services for you!");
    }
}

      



I've tested it a bit and it seems to work. Surely the challenge is where else is there a 401 with a String response body? I would have to check more to see if this covers everything.

0


source


This is how I do it:

@POST
@Consumes("application/json")
@Produces("application/json")
public Response create(Entity entity) {
    try {
        Entity created = service().create(entity);
        return Response.created(location(created)).entity(created).build();
    } catch (ServiceException e) {
        return Response.status(e.getStatus()).entity(e).build();
    }
}

      



Note the return type, Response . This allows you to customize the response, including header settings, etc. This also means that you need to write some more connection code.

I am using a custom one ServiceException

here which already has a status in it and use that to set the response code. Then I pass the exception itself, which will be returned as JSON.

0


source







All Articles