2

We are using Spring MVC ver 4.3 in one of the projects. The application supports i18n and Locale can be changed using url like http://appurl.com/?locale=en
The problem is when someone sends random value for locale, it is not rejected, rather Spring sets Content-Language header value = that_random_str
And since we are using CookieLocaleResolver, Spring also sets localeCookie value to that_random_str. Is there any way where we can tell Spring to restrict locale values to only few Locales like only English(en) and Hindi(hi) are allowed and IllegalArgumentException shall be thrown for other values

Chetan Ahirrao
  • 1,454
  • 11
  • 16
  • 1
    Why not validate this in the same way you would validate any other user-provided input? [How to validate a locale in java?](https://stackoverflow.com/q/3684747/12567365) If you only want to support a very small list of predefined values, then it becomes even simpler - use a properties list, or an enum, etc. to provide the set of valid values. Return `400 Bad Request` (and explanation) to the user if the validation fails. – andrewJames May 12 '23 at 12:57
  • (Java [does not validate locale data](https://download.java.net/java/early_access/panama/docs/api/java.base/java/util/Locale.html): "_the Locale class does not provide any validation features. The Builder only checks if an individual field satisfies the syntactic requirement (is well-formed), but does not validate the value itself._". Sounds like Spring doesn't either. So, you have to do it.) – andrewJames May 12 '23 at 12:58

1 Answers1

1

Couldn't find any standard solution to this so solved it with my own way.
I extended LocaleChangeInterceptor and overridden preHandle method.

public class CustomLocaleChangeInterceptor extends LocaleChangeInterceptor{

    private Set<String> validLanguages;
    
    public CustomLocaleChangeInterceptor() {
        super();
    }
    
    public Set<String> getValidLanguages() {
        return validLanguages;
    }

    public void setValidLanguages(Set<String> validLanguages) {
        this.validLanguages = validLanguages;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws ServletException {

        String newLocale = request.getParameter(getParamName());
        if(newLocale!=null && !"".equals(newLocale)) {
            newLocale=newLocale.toLowerCase();
            if(!validLanguages.contains(newLocale)) {
                throw new IllegalArgumentException("Language/Locale not supported");
            }
        }
            
        return super.preHandle(request, response, handler);
    }
}

and in xml configuration:

<interceptors>
        <beans:bean
            class="mypackage.CustomLocaleChangeInterceptor">
            <beans:property name="paramName" value="language" />
            <beans:property name="validLanguages">
                <beans:set>
                    <beans:value>en</beans:value>
                    <beans:value>hi</beans:value>
                </beans:set>
            </beans:property>
        </beans:bean>
</interceptors>

Though the invalid Locale doesn't cause any issue, the security team was persistent that Locale injection is possible so I needed to do this.

Chetan Ahirrao
  • 1,454
  • 11
  • 16