Spring, property file, empty values - spring

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=\ \

Related

How do I use the appProperties with the ruby api-client

I can't determine how to add custom properties or search for them.
Everything I have tried is giving me a Error - #<Google::Apis::ClientError: invalid: Invalid query> when I attempt to search for them. I can successfully complete other queries but I don't know if the client is setup to work with appProperties (or even properties at all).
Basically I just need the correct syntax for searching and adding since it doesn't appear to be in the documentation.
Assuming you already have a reference to an authorized DriveService, you can search based on appProperties using a q-parameter (documented here), like this:
file_list = drive.list_files(
q: "appProperties has { key='my_app_key' and value='my_val' }",
fields: 'files(id, name, appProperties)',
spaces: 'drive')
If you omit the fields parameter then the search will still work but the properties themselves won't be returned.
Updating appProperties is definitely arcane and the documentation is opaque. What you need is the ID of the file, and a File value object as a container for the attributes to update. Something like this:
new_app_properties = { 'my_app_key' => 'my_val' }
update_f = Google::Apis::DriveV3::File.new(app_properties: new_app_properties)
drive.update_file(file_id, update_f)

Spring matrix parameters

I have upgraded my spring version to 4.1.4 and now want to use Matrix parameters.
I have added below to enable support for matrix parameters in configuration file:
<mvc:annotation-driven conversion-service="applicationConversionService" enable-matrix-variables="true"/>
and in code I am accessing it as below in my method:
public ResponseEntity<String> transactions(#PathVariable("accountNumber") String accountNumber,
#MatrixVariable(required = true,value="sinceDate") String sinceDate){....}
and my url is : http://localhost:8080/spring_test/accounts/8293/transactions;sinceDate=2014-01-20;untilDate=2014-01-01;
But I am getting sinceDate value as null, which is declared with #MatrixVariable.
Please suggest if I am missing any steps?
Thanks,
Manasi
If you have your own AbstractHandlerMapping definition you should specify its <beans:property name="removeSemicolonContent" value="false"/>.
Otherwise I suggest you to debug the Spring code and figure out why removeSemicolonContent isn't reseted for the default RequestMappingHandlerMapping.
The break point should be in the UrlPathHelper#removeSemicolonContent
To make this worked you should place matrix variables in the URL just after the approriate pathVariable:
http://localhost:8080/spring_test/accounts/8293;sinceDate=2014-01-20;untilDate=‌​2014-01-01;/transactions

Accesing Property files in Spring

I am new to spring and I am trying to read the values from properties file.
This is my Security XML:-
<beans:bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<beans:property name="location">
<beans:value>AuthProvider.properties</beans:value>
</beans:property>
</beans:bean>
and I am trying to access the properties in java class as follows but its returning nothing:
Properties props = PropertiesLoaderUtils.loadAllProperties("AuthProvider.properties");
PropertyPlaceholderConfigurer props2 = new PropertyPlaceholderConfigurer();
props2.setProperties(props);
for(String key : props.stringPropertyNames())
{
String value = props.getProperty(key);
System.out.println(key + " => " + value);
}
Can someone please tell me where I am goin wrong?
First of all you should show the error you get.
From other side to understand more it is better to read books and docs about a framework.
Regarding Spring you can find enough info here: https://spring.io/guides
Right now it isn't clear what is your general task.
To have just properties as bean it is enough to use:
<util:properties id="myProps" location="AuthProvider.properties"/>
However you shouldn't forget that there is need to correctly specify the location for your file: is it on classpath, on file system, some external URL etc. Here is more info: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/resources.html
At the same reference you can find out how to configure <property-placeholder> and why it is needed.
UPDATE
Just to load properties from file to the Properties object you do it correctly using PropertiesLoaderUtils.loadAllProperties. But here the resourceName should be correct relative path to the file within CLASSPATH - and it will be loaded as resource by ClassLoader.
What is bad here, we don't know where is your AuthProvider.properties, and it says that you provide for it the wrong path.

Grails define custom error message for command object

I am writing a Grails (2.3.3 currently) application and have created a validateable command object similar to the following:
#Validateable
class MyCustomCommand {
String name
static constraints = {
name blank: false
}
}
In my i18n/messages.properties file I defined the following properties to override the default error messages.
MyCustomCommand.name.blank=Name must be provided.
MyCustomCommand.name.null=Name must be provided.
Which per the Grails documentation should be of the format [Class Name].[Property Name].[Constraint Code] as I have done. When I run my application if I leave the value blank I still get the default message for a null property.
I also tried following the example of the default messages and defining them a follows, but still get the default message.
MyCustomCommand.name.blank.message=Name must be provided.
MyCustomCommand.name.null.message=Name must be provided.
I am assuming that I am missing something simple here, but have yet to stumble upon what. Any suggestions on what I am doing incorrectly?
It is simple indeed. Message should look like:
myCustomCommand.name.blank=Name must be provided.
myCustomCommand.name.nullable=Name must be provided.
//className.propertyName.blank (camelCase with first letter of class name lower)
So, as I anticipated it was something simple. I was using the defaults as an example which used null where as what I really needed was nullable. Which does make sense as that matches the constraint name.
Therefore the correct version is:
myCustomCommand.name.blank=Name must be provided.
myCustomCommand.name.nullable=Name must be provided.

Spring MVC Portlets: external pagination with displaytag needs to go to the action phase

I'm using Spring MVC portlets I need to implement one display tag with external pagination. In order to do this, I've defined my table in the JSP like this:
<portlet:actionURL var="viewListURL">
<portlet:param name='action' value='${ServletContextKeys.MY_ACTION_METHOD}'/>
</portlet:actionURL>
<display:table name="${whateverList}"
requestURI="${viewListURL}"
class="displayTagTable"
export="true"
uid="item"
pagesize="10"
partialList="true"
sort="external"
defaultsort="1"
size="${ServletContextKeys.SC_LIST_SIZE}">
...
The problem is that, when I click any button to paginate, the displaytag redirects me to the render phase instead the action phase as I want to. What am I doing wrong? Any ideas..?
Thanks a lot
EDIT: I can see in the URL that the parameter p_p_url_type=0 (render phase). it makes no sense to me, as I'm calling an action url, but maybe would be enough just change this parameter to p_p_url_type=1. But, I'm just don't know how... Any ideas?
http://localhost:8080/wsdes/user/sifo3/home?p_p_id=SifoIIIweb_WAR_sifo3economicoweb_INSTANCE_s8jH&p_p_lifecycle=1&p_p_url_type=0&p_p_state=maximized&p_p_mode=view&_SifoIIIweb_WAR_sifo3economicoweb_INSTANCE_s8jH_action=consultaJustificantes&_SifoIIIweb_WAR_sifo3economicoweb_INSTANCE_s8jH_implicitModel=true&_SifoIIIweb_WAR_sifo3economicoweb_INSTANCE_s8jH_d-49489-p=2
Been there before. I solved the problem in a different way, but while looking in DisplayTag source code I found some interesting things. For example, in PortletHref you can find this in the addParameter method:
if (PARAM_TYPE.equals(name))
{
if (TYPE_RENDER.equals(value))
{
this.setAction(false);
}
else if (TYPE_ACTION.equals(value))
{
this.setAction(true);
}
And also:
private static final String PARAM_PREFIX = "portlet:";
public static final String PARAM_TYPE = PARAM_PREFIX + "type";
public static final String TYPE_ACTION = "action";
Apparently, if you need a parameter named portlet:type with value action to make DisplayTag generate an Action URL. I haven't tested myself, so let me know if it works.
I still don't know the reason, but I fixed this issue changing the display tag for Portlets (displaytag-portlet.jar), to the standard displaytag, and deleting from the displaytag.properties file the factory.requestHelper property:
factory.requestHelper=org.displaytag.portlet.PortletRequestHelperFactory
Using the normal displaytag library, instead of the portlet one, fixed my problems.

Resources