petstore URL not disabled in SpringDoc OpenAPi - swagger-ui

I am using SpringDoc 1.4.3 for swagger. I have added the below configuration to disabled the petstore URLs in application.yml
Configuration
springdoc:
swagger-ui:
disable-swagger-default-url: true
tags-sorter: alpha
operations-sorter: alpha
doc-expansion: none
but when I hit the https://petstore.swagger.io/v2/swagger.json in explore text box, it is still showing me the petsore URLs as shown in the below image.
Swagger Image

Already tested and validated thanks to the following feature support:
https://github.com/springdoc/springdoc-openapi/issues/714
Just use, the following property:
springdoc.swagger-ui.disable-swagger-default-url=true

For those if the suggested property setting did not work, clear the browser cache and reload the URL. The property setting DOES WORK. Wasted 2 hours to figure it out.
springdoc:
swagger-ui:
disable-swagger-default-url: true

The only way I got around this was by adding a SwaggerConfig page [tutorial here] and changing to OAS_3 and saving, and then you can either change it to something else after.
return new Docket(DocumentationType.OAS_30)
It just seems like Swagger is keeping a cache or something, but saving a configured OAS_3 seems to let Swagger know to stop using the default.

In my case, I had an incorrectly-defined servlet filter - I was missing a 'return;' statement. This caused the filter chain to not be processed properly, and some of the Swagger requests got borked.
Check to see if you have the following condition:
#Component
public class MyFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
if (some condition) {
chain.doFilter(request, response);
return; /**** Don't forget this line! ****/
}
... more logic ...
chain.doFilter(request, response);
}
}

Set below property, this will disable Swagger OpenApi 3 UI module
springdoc.api-docs.enabled=false

Related

MockMvc: changing default character encoding of MockHttpServletResponse from ISO-8859-1 to UTF-8

While writing Spring Itegration Tests I had the problem that MockMvc ignored my
.accept(MediaType.APPLICATION_JSON_UTF8)
setting, and returned ISO-8859-1 with bad looking umlaut.
What is the best way to set default encoding of MockMvc to UTF-8?
I read that in spring boot the following setting would help.
spring.http.encoding.force=true
In my case, where the setup is a bit special, it did not.
What does work for my setup is adding a filter to the MockMvc setup.
#Before
public void setUp() {
mockMvc = MockMvcBuilders
.webAppContextSetup(webApplicationContext)
.addFilter((request, response, chain) -> {
response.setCharacterEncoding("UTF-8"); // this is crucial
chain.doFilter(request, response);
}, "/*")
.build();
}
Hope it helps someone and saves some hours of try and error.
This worked for me:
server.servlet.encoding.charset=UTF-8
server.servlet.encoding.force=true
I got the idea from this SO Question: SpringBoot response charset errors
This worked for me (Spring Framework 5.3.18):
MockMvcBuilders.defaultResponseCharacterEncoding(StandardCharsets.UTF_8)
For example:
MockMvc mockMvc = MockMvcBuilders
.standaloneSetup(controller)
.defaultResponseCharacterEncoding(StandardCharsets.UTF_8)
.build();

Spring OAuth2 - There is no client authentication. Try adding an appropriate authentication filter

We have an application which is using spring-security-oauth2:1.0. I was trying to change it to a newer version, spring-security-oauth2:2.0.7.RELEASE. Some classes were removed, some package structure is changed, I managed to sort out all those things and I was able to start the server without any issue. But I am facing a strange issue here.
With OAuth2 - 1.0 version, when the user logs in we used to do a GET request on /oauth/token, For example :
http://localhost:8080/echo/oauth/token?grant_type=password&client_id=ws&client_secret=secret&scope=read,write&username=john#abc.com&password=password123
and It used to work just fine.
When I try the same thing, First of all I am not able to make a GET request because of the logic in TokenEndPoint.java
private Set<HttpMethod> allowedRequestMethods = new HashSet<HttpMethod>(Arrays.asList(HttpMethod.POST));
#RequestMapping(value = "/oauth/token", method=RequestMethod.GET)
public ResponseEntity<OAuth2AccessToken> getAccessToken(Principal principal, #RequestParam
Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
if (!allowedRequestMethods.contains(HttpMethod.GET)) {
throw new HttpRequestMethodNotSupportedException("GET");
}
return postAccessToken(principal, parameters);
}
I have tried to make a POST request same as above URL, but I get InsufficientAuthenticationException with the error message
There is no client authentication. Try adding an appropriate authentication filter
This is because of the following POST request controller in TokenEndpoint.java. When I debug, I see that principal is null.
#RequestMapping(value = "/oauth/token", method=RequestMethod.POST)
public ResponseEntity<OAuth2AccessToken> postAccessToken(Principal principal, #RequestParam
Map<String, String> parameters) throws HttpRequestMethodNotSupportedException {
//principal is null here
if (!(principal instanceof Authentication)) {
throw new InsufficientAuthenticationException(
"There is no client authentication. Try adding an appropriate authentication filter.");
}
.............
}
I have an authentication filter and it worked well when I used version 1.0. This is the relevant prats of my config:
<authentication-manager xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="userDetailsService"/>
</authentication-manager>
<bean id="userDetailsService" class="com.hcl.nc.service.UserDetailsService">
<constructor-arg><ref bean="sessionFactory" /></constructor-arg>
</bean>
I always thought that the request will be authenticated by authentication-provider and goes to token-endpoint but that does not seem to be the correct flow. After debugging the application with version 2.0.7, now I really doubt my understanding about the flow.
Could somebody please explain why it worked in previous version and why it's not working now?
Do I have do to something different to get a OAuth token??
NOTE: I have already checked these questions : here, here, here. But I was not able to find the correct solution.
I don't know the previous version, but I know a bit about 2.0.7.
I suspect your problem is that your TokenEndpoint security tries to authenticate your clients against your user service.
The TokenEndpoint is protected by a BasicAuthenticationFilter. By default this filter would use an AuthenticationManager instance, which itself holds an AuthenticationProvider, which itself depends on an instance of UserDetailsService.
The trick is that this particular instance of UserDetailsService must be client based, not user based : that's why there is a ClientDetailsUserDetailsService, which adapts ClientDetailsService to UserDetailsService.
Normally all this stuff is already done by default when you use the framework's configuration classes AuthorizationServerConfigurerAdapter, #EnableAuthorizationServer, etc..
I had the same problem and my application.yml had this line:
servlet:
path: /auth
so the token address was: /auth/oauth/token
I remove the path from application.yml so the token path became:
/oauth/token
And everything works fine.
I hope this help
One of the problems of the following error, can be that authentication was not performed. I have encountered this problem with older implementation of Spring.
verify that:
TokenEndpoint -> postAccessToken method. Check if Principal is not null. If it is null it means that Basic Authroziation was not performed.
One of the solution to add filter was to use:
#Configuration
public class FilterChainInitializer extends AbstractSecurityWebApplicationInitializer {
}
More information about AbstractSecurityWebApplicationInitializer can be found in Spring docs
The problem can be because of opening all requests. You should remove it.
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/**");
}
in my case, i found this config:
security.allowFormAuthenticationForClients(); // here
then post this
http://localhost:8081/sso/oauth/token?client_id=unity-client&client_secret=unity&grant_type=authorization_code&code=Yk4Sum&redirect_uri=http://localhost:8082/sso-demo/passport/login
its works for me, try it
#Configuration
#EnableAuthorizationServer
public class Oauth2Config extends AuthorizationServerConfigurerAdapter {
private static final Logger log = LoggerFactory.getLogger(Oauth2Config.class);
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.allowFormAuthenticationForClients(); // here
}
#Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception { // #formatter:off
clients.inMemory()
.withClient("unity-client")
.secret("unity")
.authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit", "refresh_token")
.scopes("foo", "read", "write")
.accessTokenValiditySeconds(3600) // 1 hour
.refreshTokenValiditySeconds(2592000) // 30 days
;
} // #formatter:on
#Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
}
}
I am following this tutorial - Practical Guide to Building an API Back End with Spring Boot'. See https://www.infoq.com/minibooks/spring-boot-building-api-backend , But with the latest SpringBoot Version(2.7)
and I run into this problem:
org.springframework.security.authentication.InsufficientAuthenticationException: There is no client authentication. Try adding an appropriate authentication filter. at org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(TokenEndpoint.java:91) ~[spring-security-oauth2-2.3.5.RELEASE.jar:na]
My solution/fix was to annotate WebSecurityGlobalConfig with #EnableWebSecurity because in the original course this annotation was missing.
So adding this annotaiton has fixed the error for me.

Servlet filter doesn't respond on given URL pattern

I have a JSF web application where all the pages that reside under directory web needs to be protected from unautheticatd use i.e., user should be in session to accesss these pages. I am using filter to validate the session for these pages. These pages are accessed via url like : /contextRoot/web/download.xhtml or /contextRoot/web/sign/upload.xhtml. Whereas other pages that reside outside web directory or in some other directory need not to go pass through session validation filter. My filter is like:
#WebFilter(filterName = "AuthenticationFilter", urlPatterns={"/web/*"}, dispatcherTypes = {DispatcherType.REQUEST})
public class AuthenticationFilter implements Filter {
private static final boolean debug = true;
private FilterConfig filterConfig = null;
public AuthenticationFilter() {
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
if (debug) {
log("AuthenticationFilter:doFilter()");
}
HttpSession session = ((HttpServletRequest) request).getSession(false);
if (session == null || session.getAttribute("username") == null) {
System.out.println("Your Session Not Active. You are redirected.");
//((HttpServletResponse) response).sendRedirect("home.xhtml");
} else {
System.out.println("Your Session is active. username : " + session.getAttribute("username"));
}
Throwable problem = null;
try {
chain.doFilter(request, response);
} catch (Throwable t) {
// If an exception is thrown somewhere down the filter chain,
// we still want to execute our after processing, and then
// rethrow the problem after that.
problem = t;
t.printStackTrace();
}
}
}
I am using urlPattern /web/* so that every page inside web directory will go pass this filter. The filter is right now just printing stuff for debugging. But whenever I am accessing page inside web directory or any other page, it is not going through filter. I also tried using /faces/web/* as urlPattern but that also didn't work. But when I put /* as urlPattern, every accessed page goes through the filter.
I am accessing page as
http://localhost:8080/CodesignWebApp/faces/web/sign/SelectServer.xhtml http://localhost:8080/CodesignWebApp/faces/web/sign/FileUpload.xhtml?signmethod=MICROSOFT
I am suspecting something wrong with urlPattern.
I am accessing page as
http://localhost:8080/CodesignWebApp/faces/web/sign/SelectServer.xhtml
http://localhost:8080/CodesignWebApp/faces/web/sign/FileUpload.xhtml
The URL pattern of a #WebFilter (and #WebServlet) must match exactly those URLs you see in browser's address bar (and thus not the disk file system paths you actually have in the server side; it's also literally called an "URL pattern", not "file pattern" or whatever).
So, all in all, just this should do, provided that /CodesignWebApp is webapp's context root:
#WebFilter("/faces/web/*")
public class AuthenticationFilter implements Filter {
// ...
}
(filter name is not relevant and request dispatcher method you specified is the default already)
A different alternative is to get rid of ancient JSF 1.0 style /faces/* mapping altogether and replace it by the JSF 2.0 style *.xhtml mapping. You don't want the endusers to see raw JSF source code when they remove /faces part from the URL, right?
<servlet-mapping>
<servlet-name>facesServlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
This way you can just access the pages as follows:
http://localhost:8080/CodesignWebApp/web/sign/SelectServer.xhtml
http://localhost:8080/CodesignWebApp/web/sign/FileUpload.xhtml
And map the filter as follows:
#WebFilter("/web/*")
public class AuthenticationFilter implements Filter {
// ...
}
See also:
JSF Facelets: Sometimes I see the URL is .jsf and sometimes .xhtml. Why?

Primefaces DialogFramework - How to show a dialog located in WEB-INF?

I am using Primefaces DialogFramework with
Primefaces 5.0
Mojarra 2.1.27
Glassfish 3.1.2.2 Build 5
My problem is, that if the user knows the location of my dialog, he is able to access it directly via the URL. I do not want that to be possible, so I thought it would be able to put the dialog in WEB-INF folder of my web-app, but now, if I want to open the dialog, I get a FileNotFound-Exception.
If my dialog is located in some regular folder, it works fine
RequestContext.getCurrentInstance().openDialog("/myfolder/mydialog");
// this works as expected
but if it is located in WEB-INF, it does not work any longer
RequestContext.getCurrentInstance().openDialog("/WEB-INF/mydialog",options,null);
// this is causing a fileNotFoundException
I also tried to set up a navigation rule for this in faces-config but again with no success
<navigation-case>
<from-outcome>mydialog</from-outcome>
<to-view-id>/WEB-INF/mydialog.xhtml</to-view-id>
<redirect />
</navigation-case>
How may I open dialogs located in WEB-INF folder, or is it not possible at all?
Thanks in advance
Unfortunately, putting PrimeFaces Dialog Framework dialogs in /WEB-INF in order to prevent direct access is indeed not going to work. The dialogs are loaded entirely client side. On the POST request which opens the dialog, JSF/PrimeFaces returns an oncomplete script with the (public!) URL of the dialog to JavaScript/jQuery, which in turn shows a basic dialog template with an <iframe> whose URL is set to the dialog URL, which in turn loads the content. In effects, 2 requests are being sent, the first to get the dialog's URL and the second to get the dialog's content based on that URL in the <iframe>.
There's no way to keep the dialog in /WEB-INF without falling back to the "traditional" dialog approach via <p:dialog> and conditional display via JS/CSS. There's also no way in the server side to verify based on some headers if the request is coming from an <iframe>, so that all others could simply be blocked. Your closest bet is the referer header, but this can be spoofed.
One way to minimize abuse is checking the presence of pfdlgcid request parameter (identified by Constants.DIALOG_FRAMEWORK.CONVERSATION_PARAM) when a dialog is being requested. PrimeFaces namely appends this request parameter representing "conversation ID" to the dialog URL. Presuming that all dialogs are stored in a folder /dialogs, then you could do the job with a simple servlet filter. Here's a kickoff example which sends a HTTP 400 error when /dialogs/* is being requested without the pfdlgcid request parameter.
#WebFilter("/dialogs/*")
public class DialogFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String id = request.getParameter(Constants.DIALOG_FRAMEWORK.CONVERSATION_PARAM);
if (id != null) {
chain.doFilter(req, res); // Okay, just continue request.
}
else {
response.sendError(HttpServletResponse.SC_BAD_REQUEST); // 400 error.
}
}
// ...
}
However, the abuser might not be that stupid and discover the pfdlgcid request parameter during the normal flow and still be able to open the dialog individually when supplying that parameter, even with a random value. I thought of comparing the actual pfdlgcid value to the known ones. I checked the PrimeFaces DialogNavigationHandler source code, but unfortunately, PrimeFaces doesn't store this value anywhere in the session. You'd need to provide a custom DialogNavigationHandler implementation wherein you store the pfdlgcid value in the session map which in turn is also compared in the servlet filter.
First add the following method to the DialogFilter:
public static Set<String> getIds(HttpServletRequest request) {
HttpSession session = request.getSession();
Set<String> ids = (Set<String>) session.getAttribute(getClass().getName());
if (ids == null) {
ids = new HashSet<>();
session.setAttribute(getClass().getName(), ids);
}
return ids;
}
Then copypaste the PrimeFaces DialogNavigationHandler source code into your own package and add the following line after line 62:
DialogFilter.getIds((HttpServletRequest) context.getExternalContext().getRequest()).add(pfdlgcid);
Replace the <navigation-handler> in faces-config.xml with the customized one.
Finally, alter the if condition in the DialogFilter#doFilter() method as follows:
if (getIds(request).contains(id)) {
// ...
}
Now, this prevents the abuser from attempting to open the dialog with a random ID. This however doesn't prevent the abuser from attempting to open the dialog by copypasting the exact <iframe> URL immediately after opening it. Given the way how the PrimeFaces dialog framework works, there's no way to prevent that. You could at most remove the pfdlgcid value from the session when the dialog is about to returns to the parent. However, when the dialog is closed by pure JS means, then this is also bypassed.
All in all, if you really, really, want to avoid the enduser being able to open the dialog individually, then you can't go around the "traditional" <p:dialog> approach.

Glassfish JSF 2.0 charset problem

I'm working on a project developed with JSF 2.0 (Mojarra 2.0.3) front end and deployed on Glassfish v.3.0.1 server. Application must accept ISO-8859-2 charset and write data to MySql database.
To problem is that data is not in right charset.
The request Http header has attribute value:
content-type: application/x-www-form-urlencoded; charset=UTF-8
The problem is not with response, since data can be displayed correctly when read from database. Also, MySql connection URL should be correct because it is set for latin2 collaction. I even tried with creating custom filter, but without any result.
Any ideas how can I accomplish to accept correct charset?
Thanks in advance.
You can always force ISO-8859-2 encoding by creating a Filter and defining it in your web.xml. At a bare minimum, the Filter should have:
public class CustomFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
if ((request instanceof HttpServletRequest)
&& (response instanceof HttpServletResponse)) {
request.setCharacterEncoding("ISO-8859-2");
response.setContentType("text/html; charset=ISO-8859-2")
}
chain.doFilter(request, response);
} catch (Exception e) {
// Do your logging here
}
}
}

Resources