2

I have a rest API implemented in Java (MSF4J codegen from swagger) and a swagger 2 definition that describes it. A swagger UI is hosted on a web server. The API is deployed on a VM somewhere on the internet.

My Problem is that the "try it out" function of the swagger UI doesn't work. I always get a "401 Unauthorized". When I take the curl command from the UI and paste it into my terminal it works.

Last week I didn't have HTTPS or Basic Authentication - just HTTP - and it worked fine. Now I don't know why it doesn't work.

Since I changed the swagger definition to https the UI makes an OPTIONS request. I implemented that, but I get 401 responses.

The certificate comes from Lets Encrypt and is used by an apache web server. The apache is a proxy to the rest api on the same machine.

Here is my authentication interceptor:

public class BasicAuthSecurityInterceptor extends AbstractBasicAuthSecurityInterceptor {

    @Override
    protected boolean authenticate(String username, String password) {
        if (checkCredentials(username, password))
            return true;
        return false;
    }

    private boolean checkCredentials(String username, String password) {
        if (username.equals("testuser"))
            return BCrypt.checkpw(password, "$2a$10$iXRsLgkJg3ZZGy4utrdNyunHcamiL2RmrKHKyJAoV4kHVGhFv.d6G");
        return false;
    }
}

Here is a part of the api:

public abstract class DeviceApiService {
    private static final Logger LOGGER = LogManager.getLogger();

    public abstract Response deviceGet() throws NotFoundException;

    public abstract Response deviceIdAvailableLoadGet(Integer id, Long from, Long to, String resolution)
        throws NotFoundException;

    public abstract Response deviceIdGet(Integer id) throws NotFoundException;

    protected Response getOptionsResponse() {
        String allowedOrigin = "";
        try {
            allowedOrigin = PropertyFileHandler.getInstance().getPropertyValueFromKey("api.cors.allowed");
        } catch (IllegalArgumentException | PropertyException | IOException e) {
            LOGGER.error("Could not get allowed origin.", e);
        }
        Response response = Response.ok().header("Allow", "GET").header("Access-Control-Allow-Origin", allowedOrigin)
            .header("Access-Control-Allow-Headers", "authorization, content-type").build();
        return response;
    }
}


public class DeviceApi {
    private final DeviceApiService delegate = DeviceApiServiceFactory.getDeviceApi();

    // @formatter:off
    @GET
    @Produces({ "application/json" })
    @io.swagger.annotations.ApiOperation(
        value = "Get devices",
        notes = "",
        response = Device.class,
        responseContainer = "List",
        authorizations = { @io.swagger.annotations.Authorization(value = "basicAuth") },
        tags = { "Device", }
    )
    @io.swagger.annotations.ApiResponses(
        value = { @io.swagger.annotations.ApiResponse(
                    code = 200,
                    message = "200 OK",
                    response = Device.class,
                    responseContainer = "List")
        })
    public Response deviceGet() throws NotFoundException {
        return delegate.deviceGet();
    }

    @OPTIONS
    @Consumes({ "application/json" })
    @Produces({ "application/json" })
    @io.swagger.annotations.ApiOperation(value = "CORS support", notes = "", response = Void.class, authorizations = {
            @io.swagger.annotations.Authorization(value = "basicAuth") }, tags = { "Device", })
    @io.swagger.annotations.ApiResponses(value = {
            @io.swagger.annotations.ApiResponse(code = 200, message = "Default response for CORS method", response = Void.class) })
    public Response deviceOptions() throws NotFoundException {
        return delegate.getOptionsResponse();
    }
}

EDIT:

This are the headers of the request the swagger ui creates:

Accept: text/html,application/xhtml+xm…plication/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: de,en-US;q=0.7,en;q=0.3
Access-Control-Request-Headers: authorization
Access-Control-Request-Method: GET
Connection: keep-alive
DNT: 1
Host: api.myfancyurl.com
Origin: http://apidoc.myfancyurl.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; …) Gecko/20100101 Firefox/61.0

It seems that the authorization header is missing. When I edit the request and resend it with the authorization header and encoded credentials it works. But I don't know why swagger doesn't add this header. Should one accept all options requests without authorization?

JWo
  • 650
  • 1
  • 6
  • 23
  • 1
    Did you debug the Interceptor and check why it throws 401? – Thusitha Thilina Dayaratne Jul 31 '18 at 05:15
  • It throws it because swagger doesn't send the authorization header, when performing an options request. When I add the "authorization" header with the encoded credentials to the request, I get a 200 ok. But why does swagger not add it by itself? – JWo Aug 01 '18 at 12:37

0 Answers0