Suspicious URL pattern in FilterRegistrationBean? - spring

Recently I'm getting the following warning when starting my spring-boot application:
o.a.c.c.StandardContext: Suspicious URL pattern: [/rest/**] in context [], see sections 12.1 and 12.2 of the Servlet specification
Definition:
#Bean
public FilterRegistrationBean traceFilterRegistration(HttpTraceFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean(filter);
registration.addUrlPatterns("/rest/**");
return registration;
}
Question: is nowadays /rest/* the same as /rest/** so I could switch that safely?
My goal is obviously to catch any sub path under the rest path, eg also /rest/this/is/my/sub.

The specs for Servlet 3.1 and 4.0 state the following:
12.2 Specification of Mappings
In the Web application deployment descriptor, the following syntax is used to define
mappings:
■ A string beginning with a ‘/’ character and ending with a ‘/*’ suffix is used for
path mapping.
■ A string beginning with a ‘*.’ prefix is used as an extension mapping.
■ The empty string ("") is a special URL pattern that exactly maps to the
application's context root, i.e., requests of the form http://host:port/<contextroot>/. In this case the path info is ’/’ and the servlet path and context path is
empty string (““).
■ A string containing only the ’/’ character indicates the "default" servlet of the
application. In this case the servlet path is the request URI minus the context path
and the path info is null.
■ All other strings are used for exact matches only.
If the effective web.xml (after merging information from fragments and
annotations) contains any
Which means the pattern /rest/** is an invalid one and should be changed to /rest/*.

Related

Spring-boot Api not starting

APPLICATION FAILED TO START
Description:
Configuration property name 'carWasher' is not valid:
Invalid characters: 'W'
Bean: carWasher-com.carWasher.properties.CarWasherProperties
Reason: Canonical names should be kebab-case ('-' separated), lowercase alpha-numeric characters and must start with a letter
Action:
Modify 'carWasher' so that it conforms to the canonical names requirements.
You have a #ConfigurationProperties bean in your application with the prefix attribute set to carWasher It should be car-washer.

What is the use of star(*) in yaml file?

I was going through spring boot actuator when I stumbled upon this quote:
* has a special meaning in YAML, so be sure to add quotes if you want to include (or exclude) all endpoints.
I tried to look over the internet about it without any luck. What is the use of * in yaml file?
* is used to remove the repeated nodes. Consider this yaml example:
myprop:
uid: &id XXX
myprop1:
id: *id
The above will expand to:
myprop:
uid: XXX
myprop1:
id: XXX
Now try running this code:
#Value("${myprop.uid}") String uid;
#Value("${myprop1.id}") String id;
#Bean
ApplicationRunner runner() {
return args -> {
System.out.println(uid); // prints "XXX"
System.out.println(id); // prints "XXX"
System.out.println(uid.equals(id)); // prints "true"
};
}
From the spec:
Repeated nodes (objects) are first identified by an anchor (marked with the ampersand - “&”), and are then aliased (referenced with an asterisk - “*”) thereafter.
It depends on the context of the YAML file. You said you was going through spring boot actuator, so you can take a look into the reference documentation of Spring Boot, the chapter 5.2.2. Exposing Endpoints to be exact.
* can be used to select all endpoints. For example, to expose everything over HTTP except the env and beans endpoints, use the following properties:
management.endpoints.web.exposure.include=*
management.endpoints.web.exposure.exclude=env,beans
The asterisk * means that all the endpoints that belongs to a certain category are either included or exluded.
The sentence below just says that the asterisk * character must be quoted "*" in case of the YAML format usage over classic properties file.
* has a special meaning in YAML, so be sure to add quotes if you want to include (or exclude) all endpoints, as shown in the following example:
By the way, this sentence is the same one you have sited at your question.

Watch for updated properties in Wicket

In my current project we need to implement a way for texters to manage the wicket messages/internationalization via upload of property files.
Also see this question: Administrating internationalized wicket applications
As suggested there, I've implemented a custom IStringResourceLoader and added it at the beginning of the StringResourceLoader list to override any properties already in place:
getResourceSettings().getStringResourceLoaders().add(0, new CustomStringResourceLoader());
This however is not enough, because updates can happen and need to be loaded at runtime. StringResources are cached by wicket and updated only when the ResourceWatcher is triggered.
I found where Wicket adds the string resources to the watcher: the PropertiesFactory in the settings. The method to add a resource to the watcher is addToWatcher(...). However this method is protected and also the whole setup suggests this is used for development purposes and not for production.
I managed to use this method by extending PropertiesFactory and effectively creating a custom version to add to settings:
getResourceSettings().setPropertiesFactory(new CustomPropertiesFactory(getResourceSettings()));
getResourceSettings().setResourcePollFrequency(Duration.seconds(1));
So my Question is: I feel this is quite the circuitious solution. Is there another way to watch for changing properties files?
My solution to the problem:
getResourceSettings().getStringResourceLoaders().add(0, new CustomResourceLoader());
getResourceSettings().getResourceFinders().add(new Path("/pathToResources"));
getResourceSettings().setResourcePollFrequency(Duration.seconds(1));
This inserts my CustomResourceLoader at the beginning of the list so all properties are first checked there.
The added Path tells the PropertiesFactory to look for resources in a given arbitrary directory outside of wicket.
I needed custom names for my resource files as well, I realized this in the CustomResourceLoader:
public String loadStringResource(final Class<?> clazz, final String key, final Locale locale, final String style, final String variation) {
final String myResourceFilename = createCustomResourceFileName(locale);
final IPropertiesFactory pF = Application.get().getResourceSettings().getPropertiesFactory();
final org.apache.wicket.resource.Properties props = pF.load(clazz, myResourceFilename);
...
}
When using the PropertiesFactory to load the files, it adds them to the internal IModificationWatcher automatically.
It turns out that part of the problem was, that the resource files are in a non-standard encoding. This can be fixed by adding a special IPropertyLoader to the PropertiesFactory in the settings:
((PropertiesFactory) getResourceSettings().getPropertiesFactory()).getPropertiesLoaders().add(0,
new UtfPropertiesFilePropertiesLoader("properties", "your-favorite-encoding"));

How to reuse Spring or Java's locale lookup code?

I am doing a Spring web application.
I need to support a few locales such as ko (Korean), ru (Russian), en (English), etc.
I am able to catch what locale is from a browser via ways such as RequestContextUtils.getLocale(request) or LocaleChangeInterceptor.
However, the browser's locale may not be what my web app supports. I have to resolve it to the closet or default locale.
Basically, I need to know how to get the resolved locale given the browser's locale AND a few locale values such as ko, ru, and en.
My understanding is that Spring has such locale resolution code because it is able to find right resource bundles given a browser's locale. I am hoping to reuse Spring's code for locale resolution, but not sure how to do it. Please note that this question has nothing to do with finding the brwoser's locale or displaying proper messages.
EDIT
Based on my tracing Spring's code, it appears that Spring depends on JDK to find the exact or closest locale. I just found out this and think this is what I am looking for:
Resource Bundle Lookup Order
https://sites.google.com/site/openjdklocale/design-notes/resource-bundle-lookup-order
Please note that I don't need to find right resource bundle. I just need to get the locale the existing JDK code returns given a locale in question and a few known locales. So I am hoping to reuse existing JDK's lookup code. Any idea?
I am using JDK 7.
Thanks for any help and input!
Regards.
Short answer
Have you checked the official documentation (chapter 17.8 Using locales)? You need to configure LocaleResolver and possibly a LocaleChangeInterceptor (or write your own).
Longer description about how Spring works
Note, that resolving client's locale is different task from getting a correct resource bundle.
Spring uses LocaleResolver to get or set the current locale. There are several implementations for different strategies to LocaleResolver:
FixedLocaleResolver - will always resolve locale to predefined value (not capable of setting different locale)
SessionLocaleResolver - stores and resolves locale to value store on session under special key
AcceptHeaderLocaleResolver - this is the resolver which actually tries to get locale from the browser (not capable of setting different locale)
CookieLocaleResolver - stores and resolves locale to value stored in a browser cooke
LocaleResolver is used to populate LocaleContextHolder (btw. that is the class you should be getting locale from).
There is a second mechanism LocaleChangeInterceptor, which is able to set locale via your selected LocaleResolver based on user request parameter.
Now this infrastructure is unrelated to your resource bundles (messages.properties, messages_en.properties, ...) and the mechanism used to resolve your messages. The following examples will show why.
Example scenarios
Lets assume your resource bundles are:
messages.properties - with ru messages (default messages)
messages_ko.properties - with ko messages
Lets assume you have configured SessionLocaleResolver with default locale ru
And lets assume you have configured LocaleChangeInterceptor
SCENARIO I - First requets:
User makes first request to the application
As soon as the request reaches Spring's DispatcherServlet it queries LocaleResolver to get locale for the request
No locale is set on the session, so the locale is resolved to ru (default)
...handler stuff...
Now you are rendering the webpage and you want to use <spring:message> tag...
The tag tries to resolve translation code using preconfigured MessageSource (ResourceBundleMessageSource) with request locale (this is the one resolved by your resolver).
Message source tries to load translation code from messages_ru.properties which does not exist, so it moves to more general file messages.properties (which "by accident" contains your default language - ru)
User get his page in russian language
SCENARIO II - User clicks link to change his language to ko:
Second request is made with query parameter locale=ko
DispatcherServlet resolves request locale to ru (this is what your locale resolver returns)
Before the request is handed over to your handler it goes through the LocaleChangeInterceptor handler interceptor.
LocaleChangeInterceptor detects locale query parameter and calls setLocale method on your LocaleResolver, which leads to changing request locale and storing new locale on the session for future requests.
...handler stuff...
...view stuff...
Now <spring:message> is calling MessageSource with ko locale.
Message source tries to load messages_ko.properties and succeeds.
User get his page in korean language
SCENARIO III - User tries to change to invalid locale:
User makes request with query parameter locale=en.
...dispatcher stuff... (locale is resolved to ko from the session)
Handler interceptor changes the locale to en (this will be stored on the session as well)
...handler stuff...
...view stuff...
Now <spring:message> is calling MessageSource with en locale.
Message source tries to load messages_en.properties which does not exist so it moves to a more general file messages.properties and messages are translated to ru, even thou the request locale is set to en.
User get his page in rusian language
Summary
Now the last example is probably what bothers you - there is no check whether the locale user selects is supported or not. If you don't want to allow user to switch to unsupported locale, then you need to either subclass some LocaleResolver or write your own LocaleChangeInterceptor.
Complete Reuse
To reuse the JDK logic, you could create a property file within the classpath for each of the known locales (such as test_fr_CA.properties, test_fr.properties, test_en_US.properties, test_en.properties, test.properties). Don't forget the root locale (test.properties) if you want to be able to match to it. Then simply create a resource bundle for the locale in question and inspect it to see the actual locale used.
ResourceBundle rb = ResourceBundle.getBundle("test", Locale.FRENCH);
System.out.println("Locale used is:"+rb.getLocale().toString());
The files can be created dynamically and cleaned up after the test.
High Level Code Replication, Low Level Reuse
You could replicate the high level code in java.util.ResourceBundle.getBundleImpl(...). This is basically going through looking for a match (using your own matching logic like equal toString() representations) in a candidate list of locales reusing java.util.ResourceBundle.Control.getCandidateLocales(...) on the locale in question. If there is no match you get the next fallback locale for the locale in question by reusing java.util.ResourceBundle.Control.getFallbackLocale(...) For each fallback locale you try to match a locale in it's candidate list repeating the fallback in a loop until there are no fallback locales left. Note that the root locale will be the last candidate in each candidate list but it should be skipped unless you have exhausted all fallback locales.
This method does not require creating files. You use a non-existent baseName in the getCandidateLocales(...) and get FallbackLocale(...) calls and compare each candidate locale to your list of known locales looking for a match.
A simple example of this would be like the following:
ResourceBundle.Control rbControl = ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_PROPERTIES);
Locale localeInQuestion = Locale.CHINA;
List<Locale> knownLocales = Arrays.asList(new Locale[] {Locale.CANADA_FRENCH, Locale.FRENCH, Locale.US, Locale.UK, Locale.ENGLISH, Locale.ROOT});
String nonExistentBaseName = "bogus";
Locale matchingLocale = null;
Boolean reachedRootLocaleMatch = false;
outerloop:
for (Locale targetLocale = localeInQuestion;
targetLocale != null;
targetLocale = rbControl.getFallbackLocale(nonExistentBaseName, targetLocale)) {
List<Locale> candidateLocales = rbControl.getCandidateLocales(nonExistentBaseName, targetLocale);
for (Iterator iterator = candidateLocales.iterator(); iterator.hasNext();) {
Locale currentCandidateLocale = (Locale) iterator.next();
if (knownLocales.contains(currentCandidateLocale)) {
if (currentCandidateLocale.equals(Locale.ROOT)) {
reachedRootLocaleMatch = true;
}
else {
matchingLocale = currentCandidateLocale;
break outerloop;
}
}
}
}
if (matchingLocale == null && reachedRootLocaleMatch) {
matchingLocale = Locale.ROOT;
}
if (matchingLocale != null) {
System.out.println("The matching locale is: "+matchingLocale.toString());
}
else {
System.out.println("There was no matching locale");
}

Spring, property file, empty values

I have configured spring security with a ldap server (but continue reading, it's not a problem if you have no knowledge about it, this is really a spring problem). All runs like a charm. Here is the line I use for that:
<ldap-server ldif="" root="" manager-dn="" manager-password="" url="" id="ldapServer" />
If I fill ldif and root attributes, it will run an embeded server:
<ldap-server ldif="classpath://ldap.ldif" root="dc=springframework,dc=org" manager-dn="" manager-password="" url="" id="ldapServer" />
If I fill other fields, it will run a distant server:
<ldap-server ldif="" root="" manager-dn="dc=admin,dc=springframeworg,dc=org" manager-password="password" url="ldap://myldapserver.com/dc=springframeworg,dc=org" id="ldapServer" />
All this stuff run correctly. Now I want to use Spring mechanism to load such parameters from a property file:
So I replace attribute values like this:
<ldap-server ldif="${ldap.ldif.path}" root="${ldap.ldif.root}" manager-dn="${ldap.server.manager.dn}" manager-password="${ldap.server.manager.password}" url="${ldap.server.url}" id="ldapServer" />
and create a property file with:
ldap.server.url=
ldap.server.manager.dn=
ldap.server.manager.password=
ldap.ldif.path=
ldap.ldif.root=
Now, the funny part of the problem. If I fill the following properties in the file:
ldap.server.url=ldap://myldapserver.com/dc=springframeworg,dc=org
ldap.server.manager.dn=dc=admin,dc=springframeworg,dc=org
ldap.server.manager.password=password
ldap.ldif.path=
ldap.ldif.root=
It runs a distant server as expected.
If I fill the property file like this:
ldap.server.url=
ldap.server.manager.dn=
ldap.server.manager.password=
ldap.ldif.path= classpath:ldap.ldif
ldap.ldif.root= dc=springframeworg,dc=org
It does not run, complaining that the ldap url is missing. But the problem is that if I change the spring configuration from:
<ldap-server ldif="${ldap.ldif.path}" root="${ldap.ldif.root}" manager-dn="${ldap.server.manager.dn}" manager-password="${ldap.server.manager.password}" url="${ldap.server.url}" id="ldapServer" />
to (by just removing the reference to the variable ${ldap.server.url})
<ldap-server ldif="${ldap.ldif.path}" root="${ldap.ldif.root}" manager-dn="${ldap.server.manager.dn}" manager-password="${ldap.server.manager.password}" url="" id="ldapServer" />
It runs !
My thoughs are that spring does not replace the attribute value with the property config one if this one is empty. But I find it strange.
Can you give me some clue to understand that ? And what's the best to do to configure my ldap server via a property file ?
EDIT: this is due to a poor design choice (look at accepted answer), an issue has been opened on jira :
https://jira.springsource.org/browse/SEC-1966
Ok, I think this is a spring security bug.
If I debug and look at the class LdapServerBeanDefinition, there is a method called "parse". Here is an extract:
public BeanDefinition parse(Element elt, ParserContext parserContext) {
String url = elt.getAttribute(ATT_URL);
RootBeanDefinition contextSource;
if (!StringUtils.hasText(url)) {
contextSource = createEmbeddedServer(elt, parserContext);
} else {
contextSource = new RootBeanDefinition();
contextSource.setBeanClassName(CONTEXT_SOURCE_CLASS);
contextSource.getConstructorArgumentValues().addIndexedArgumentValue(0, url);
}
contextSource.setSource(parserContext.extractSource(elt));
String managerDn = elt.getAttribute(ATT_PRINCIPAL);
String managerPassword = elt.getAttribute(ATT_PASSWORD);
if (StringUtils.hasText(managerDn)) {
if(!StringUtils.hasText(managerPassword)) {
parserContext.getReaderContext().error("You must specify the " + ATT_PASSWORD +
" if you supply a " + managerDn, elt);
}
contextSource.getPropertyValues().addPropertyValue("userDn", managerDn);
contextSource.getPropertyValues().addPropertyValue("password", managerPassword);
}
...
}
If I debug here, all variables (url, managerDn, managerPassword...) are not replaced by the value specified in the property file. And so, url has the value ${ldap.server.url}, managerDn has the value ${ldap.server.manager.dn} and so on.
The method parse creates a bean, a context source that will be used further. And when this bean will be used, place holders will be replaced.
Here, we got the bug. The parse method check if url is empty or not. The problem is that url is not empty here because it has the value ${ldap.server.url}. So, the parse method creates a context source as a distant server.
When the created source will be used, it will replace the ${ldap.server.url} by empty value (like specified in the property file). And....... Bug !
I don't know really how to solve this for the moment, but I now understand why it bugs ;)
I cannot explain it, but I think you can fix your problem using defaulting syntax, available since Spring 3.0.0.RC1 (see).
In the chageg log you can read: PropertyPlaceholderConfigurer supports "${myKey:myDefaultValue}" defaulting syntax
Anyway, I think that the problem is because "" is valid value, but no value in the property file don't.
I think that url="" works because url attribute is of type xs:token in spring-security XSD and empty string is converted to null (xs:token is removing any leading or trailing spaces, so "" can be recognized as no value). Maybe the value of ${ldap.server.url} is resolved as empty string and that is why you've got an error.
You can try use Spring profiles to define different configurations of ldap server (see Spring Team Blog for details about profiles)
I believe there is an issue here while using place holders. The following will most probably solve the problem:
Create a class which extends PropertyPlaceHolderConfigurer and override its method convertPropertyValue()
in the method you can return the property as empty string if you find anything other than a string which is of type LDAP url i.e. ldap://myldapserver.com/dc=springframeworg,dc=org
Also you need to configure your new specialization of class PropertyPlaceHolderConfigurer in the context file.
Hope this helps.
You can define empty String in the application.properties file as following:
com.core.estimation.stopwords=\ \

Resources