OpenAPI Specification 3.0 shows different url in browser and Servers dropdown - spring-boot

We are using OpenApi Specification v1.4.8. We have load balancer urls and domain url. Domain url http://market.place.com/productsservice/swagger-ui.html and load balancer url is http://7649263.path.aws.com/productsservice/swagger-ui.html.
Due some ongoing network issue with the domain, we have shifted to use load balancer url for testing the application. When I access swagger ui using the above load balancer url, I see the domain URL in servers dropdown(haven't added it anywhere). Thus the url in browser address bar and in Servers dropdown is different.
Since Swagger uses the base url from 'Servers' dropdown to fabricate paths for testing, and my domain is not working, I am not able to fire request from Swagger UI. The request work fine via postman when the url in browser that is load balancer url is used.
Is there some configuration which can make the Servers dropdown URL and Browser url base path same ? What we are trying to do is, the Servers dropdown needs to take the url as in the address bar of browser.

Probably you have openapi 3 configuration java class.
You should
new OpenAPI().addServersItem(...)
Edit your method like this.
private String ip="109.162.230.178"; //your ip
private String port="8587"; //your port
// if you have context add this line
private String context="tws"; //your context
#Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.addServersItem(new Server().url("http://"+ip+":"+port+"/"+context))
...
}
now your UI Combobox is like this :
For example my server static ip is
109.162.230.178
and i have to use this Openapi 3 UI
from another computer outside of my local network in Internet.

I think of the one reason why you have this issue. You should check in code if io.swagger.v3.oas.models.servers.Server is being used in OpenAPI configuration-
OpenAPI oas = new OpenAPI();
......
......
String url = "/market.place.com/"
List<Server> servers = new ArrayList<Server>();
Server server = new Server();
server.setUrl(url);
servers.add(server);
oas.setServers(servers);
If you are relying on programmatic approach for openAPI configuration and you have something like above in your code then that may be the reason why you are seeing your domain URI. You can replace it with correct URI to make it work.

Related

Redirection from Spring Boot Application of External Website

I am building a Spring Boot Application with SSL enabled.
Now when I am redirecting to some external website with leading http:// explicitly.
for example http://www.example.com. But browser is redirecting it to https://www.example.com
automatically.
As I am not sure the target site is http or https. I want to redirect to the target as it is in my database.
Is there any one could help regarding this issue?
I have tried by returning redirect:http://www.example.com and ModelAndView approach. It did not work.
Note: My action can return html view or redirect to external site.
Try This :
#RequestMapping(value = "/redirect", method = RequestMethod.GET)
public void method(HttpServletResponse httpServletResponse) {
httpServletResponse.setHeader("Location", projectUrl);
httpServletResponse.setStatus(302);
}
I tried by different ways from the Application. But it never worked.
DevOps have added Load Balancer in the middle and something messed up while setting the Load Balancer rules. They have modified at their end. Now it's working fine.

WebApi: Use different Route prefix for http reservation and WebApi routes

I have a Windows Service which exposes some APIs via WebAPI and OData using http.sys (to facilitate port sharing):
/api
/odata
/swagger
I also have reservation with http.sys for the prefix https://+:1234/.
Additionally, I have a web site (SPA) which uses this API and I'd like it to run on the same port. UP to now, this was no problem, because I had static file hosting in the service. For various reasons, I moved the static file hosting to its own service. and changed my http.sys reservation to this:
Static file hosting (Weak wildcard):
https://*:1234/
Service (strong wildcard):
https://+:1234/api/
https://+:1234/swagger/
https://+:1234/odata
And in my service I changed my
WebApp.Start("https://+:1234", Startup);
to
var options = new StartOptions
{
urls =
{
"https://+:1234/api/",
"https://+:1234/swagger/",
"https://+:1234/odata/",
}
};
_Service = WebApp.Start(options, Startup);
However, now the routes to the WebApi are https://+:1234/api/api/ and I can even use https://+:1234/api/odata/, which is kind of understandable, but not what I intended.
Can I trick WebApi that while it registers itself with http.sys on the three listening urls but always uses https://+:1234/ as the base for the routing?
This is nice question, I was tried different ways ..., But I had same experiences what you got right now....
Finally, I have understand, We can achieve your excepted out put with the UrlPrefixCollection Here is Url : https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.server.httpsys.urlprefixcollection?view=aspnetcore-2.2

Swagger page being redirected from https to http

AWS Elastic Load Balancer listening through HTTPS (443) using SSL and redirecting requests to EC2 instances through HTTP (80), with IIS hosting a .net webapi application, using swashbuckle to describe the API methods.
Home page of the API (https://example.com) has a link to Swagger documentation which can bee read as https://example.com/swagger/ui/index.html when you hove over on the link.
If I click on the link it redirects the request on the browser to http://example.com/swagger/ui/index.html which displays a Page Not Found error
but if I type directly in the browser URL https://example.com/swagger/ui/index.html then it loads Swagger page, but then, when expanding the methods an click on "Try it out", the Request URL starts with "http" again.
This configuration is only for Stage and Production environments. Lower environments don't use the load balancer and just use http.
Any ideas on how to stop https being redirected to http? And how make swagger to display Request URLs using https?
Thank you
EDIT:
I'm using a custom index.html file
Seems is a known issue for Swashbuckle. Quote:
"By default, the service root url is inferred from the request used to access the docs. However, there may be situations (e.g. proxy and load-balanced environments) where this does not resolve correctly. You can workaround this by providing your own code to determine the root URL."
What I did was provide the root url and/or scheme to use based on the environment
GlobalConfiguration.Configuration
.EnableSwagger(c =>
{
...
c.RootUrl(req => GetRootUrlFromAppConfig(req));
...
c.Schemes(GetEnvironmentScheme());
...
})
.EnableSwaggerUi(c =>
{
...
});
where
public static string[] GetEnvironmentScheme()
{
...
}
public static string GetRootUrlFromAppConfig(HttpRequestMessage request)
{
...
}
The way I would probably do it is having a main file, and generating during the build of your application a different swagger file based on the environnement parameters for schemes and hosts.
That way, you have to manage only one swagger file accross your environments, and you only have to manage a few extra environnement properties, host and schemes (if you don't already have them)
Since I don't know about swashbuckle, I cannot answer for sure at your first question (the redirect)

Is there a means to set the host & port for the Spring HATEOAS `ControllerLinkBuilder`?

Spring HATEOAS provides the handy ControllerLinkBuilder to create links to controller methods, which will be added as hrefs in the JSON/XML returned to a client. For instance:
resource.add(linkTo(methodOn(FooController.class)
.findFoo(entity.getClient().getId()))
.withRel("show"));
... might generate JSON a bit like:
{
"name":"foo",
"links":[
{"rel":"show","href":"http://111.11.11.111:28080/foos/1"}
]
}
However...
I tend to access my services through a reverse proxy. Which I guess most people probably would. This lets me have multiple services running on different ports, but lets me access them all through the same base URL. Unfortunately, accessing through a proxy means that the URL being generated by Spring HATEOAS is not a URL which is valid for accessing the resource.
Now I could just hard-code the links, but that's rather fragile. Having the ControllerLinkBuilder generate URLs based on my controller #RequestMapping configuration is valuable to me, as it avoids the risk of my links getting out of sync with reality.
So I was wondering whether there's a property somewhere that I could use to force the host and port values. I'm using Spring Boot, so ideally a property that I could add to the application.properties file in each environment.
Note:
As this issue seems to be caused by a bug in Spring, I should probably point out that I'm using Spring Boot 1.0.2.RELEASE.
A pure answer to the question I originally posed seems to involve writing my own ControllerLinkBuilder implementation which has the option of building the URL based on environment variables that I set. I may do that.
However, the reason I was trying to force the URL is that there is a bug in the ControllerLinkBuilder. It's worth noting that this bug is a bug in code which was copied from ServletUriComponentsBuilder.
String scheme = request.getScheme();
// The port number retrieved here is the port set by server.port
int port = request.getServerPort();
String host = request.getServerName();
String header = request.getHeader("X-Forwarded-Host");
if (StringUtils.hasText(header)) {
String[] hosts = StringUtils.commaDelimitedListToStringArray(header);
String hostToUse = hosts[0];
if (hostToUse.contains(":")) {
String[] hostAndPort = StringUtils.split(hostToUse, ":");
host = hostAndPort[0];
// Note that the port is set if there is a ":" in the address.
port = Integer.parseInt(hostAndPort[1]);
}
else {
host = hostToUse;
}
}
ServletUriComponentsBuilder builder = new ServletUriComponentsBuilder();
builder.scheme(scheme);
builder.host(host);
// Here lies the bug...
if ((scheme.equals("http") && port != 80) || (scheme.equals("https") && port != 443)) {
builder.port(port);
}
Basically, the port is only set when the server.port is not 80 or 443, rather than being based on the port used for the request. This means that if the X-Forwarded-Host is using a default port for the scheme (and therefore not having anything after the ":"), then the application port will be used instead of the default.
Spring-Boot uses an older version of Spring-HATEOAS, i think it was .11 that they added support for X-Forwarded-Port and X-Forwarded-Ssl headers, just add that explicit version to your POM and if your proxy is doing the right thing and adding those headers you should be good to go.
Also if your proxy can be configured to NOT rewrite the HOST header the built in controller link builder will work just fine.

Getting server name the client know behind a reverse proxy within a Java EE web application

For my Java EE web application I have a problem. I need to redirect a page A to another page B, using Spring controller I write:
Page A is for my browser (in http):
http://MYPUBLICSERVERNAME/MYCONTEXT/A.do :
In A which is a Spring controller has the following code for redirection:
#RequestMapping(method = RequestMethod.GET, value = "/A.do")
public String searchProfiles(){
....
return "redirect:/B.html";
}
It works perfectly in http.
so I go to B :
http://MYPUBLICSERVERNAME/MYCONTEXT/B.html
The problem comes with HTTPS because with HTTPS a reverse proxy intercept the request :
This proxy is on the same machine and I get :
impossible to connect because when i go to :
httpS://MYPUBLICSERVERNAME/MYCONTEXT/A.do
i expected to be redirected to :
httpS://MYPUBLICSERVERNAME/MYCONTEXT/B.html
Instead the browser is redirected to
http://localhost/MYCONTEXT/B.html
I understand that for the server the client is the reverse proxy not of course the browser.
So my question is : how can the servlet get the original server name i mean the server name indicated in the web browser (MYPUBLICSERVERNAME) and the protocol (HTTPS if HTTPS).
The workaround i think is using a cookie feeded by the browser, because the browser only know MYPUBLICSERVERNAME but maybe more elegant solution exist ?
Of course if I know a spring function that can magically redirect with expected protocol and server name it's ok too but i didn't find it.
Thanks for your answer
you can use the redirect with the whole path and protocol
return "redirect:https://MYPUBLICSERVERNAME/MYCONTEXT/B.html"
I am not sure if you can use refferer header in request (does proxy change the refferer ?)
String referrer = request.getHeader("referer");

Resources