弹簧,属性文件,空值
Posted
技术标签:
【中文标题】弹簧,属性文件,空值【英文标题】:Spring, property file, empty values 【发布时间】:2012-05-16 00:24:31 【问题描述】:我已经用ldap服务器配置了spring security(但是继续阅读,如果你不了解它也不是问题,这确实是一个spring问题)。一切都像魅力一样运行。这是我使用的那一行:
<ldap-server ldif="" root="" manager-dn="" manager-password="" url="" id="ldapServer" />
如果我填写 ldif 和 root 属性,它将运行一个嵌入式服务器:
<ldap-server ldif="classpath://ldap.ldif" root="dc=springframework,dc=org" manager-dn="" manager-password="" url="" id="ldapServer" />
如果我填写其他字段,它将运行远程服务器:
<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" />
所有这些东西都能正常运行。现在我想使用 Spring 机制从属性文件中加载这些参数:
所以我像这样替换属性值:
<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" />
并创建一个属性文件:
ldap.server.url=
ldap.server.manager.dn=
ldap.server.manager.password=
ldap.ldif.path=
ldap.ldif.root=
现在,问题的有趣部分。如果我在文件中填写以下属性:
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=
它按预期运行远程服务器。
如果我这样填写属性文件:
ldap.server.url=
ldap.server.manager.dn=
ldap.server.manager.password=
ldap.ldif.path= classpath:ldap.ldif
ldap.ldif.root= dc=springframeworg,dc=org
它没有运行,抱怨缺少 ldap url。但问题是,如果我从以下位置更改弹簧配置:
<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(只需删除对变量 $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" />
它运行!
我的想法是,如果该属性值为空,则 spring 不会将属性值替换为属性配置之一。但我觉得很奇怪。
你能给我一些线索来理解吗?通过属性文件配置我的 ldap 服务器的最佳方法是什么?
编辑:这是由于设计选择不佳(查看接受的答案),在 jira 上已打开一个问题: https://jira.springsource.org/browse/SEC-1966
【问题讨论】:
你用的是什么版本的 Spring? 【参考方案1】:好的,我认为这是一个 Spring 安全漏洞。
如果我调试并查看 LdapServerBeanDefinition 类,有一个名为“parse”的方法。这是摘录:
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);
...
如果我在这里调试,所有变量(url、managerDn、managerPassword...)都不会被属性文件中指定的值替换。因此,url 的值为 $ldap.server.url,managerDn 的值为 $ldap.server.manager.dn,依此类推。
方法 parse 创建一个 bean,一个将被进一步使用的上下文源。并且当这个 bean 将被使用时,占位符将被替换。
在这里,我们得到了错误。 parse 方法检查 url 是否为空。问题是这里的 url 不是空的,因为它的值是 $ldap.server.url。因此,parse 方法创建了一个上下文源作为远程服务器。
当使用创建的源时,它会将 $ldap.server.url 替换为空值(如属性文件中指定的)。还有.......错误!
我现在真的不知道如何解决这个问题,但我现在明白为什么它会出错;)
【讨论】:
这不是错误。如果要创建嵌入式服务器,则不应使用 url 属性。见static.springsource.org/spring-security/site/docs/3.1.x/… 我称之为错误的是,使用空字符串运行并且使用变量不会运行,因为 Spring Security 通过不将变量替换为其值(可以为空! )。这是一个糟糕的设计。 在这种情况下,我认为在 Spring 错误跟踪器中报告问题是有意义的,对吧? jira.springsource.org/secure/Dashboard.jspa 感谢提交问题,我会在今晚或明天提交;)【参考方案2】:我无法解释,但我认为您可以使用自 Spring 3.0.0.RC1 (see) 起提供的默认语法来解决您的问题。
在 chageg 日志中您可以阅读:PropertyPlaceholderConfigurer 支持“$myKey:myDefaultValue”默认语法
无论如何,我认为问题是因为“”是有效值,但属性文件中没有值。
【讨论】:
感谢您的回答,但我一直使用默认值提示相同的错误。 我不明白。如果默认值为 '' 我认为应该与将其设置为 '' 相同。 是的,我也是这么想的……很奇怪……也许,url的setter只有在我们使用spring表达式的时候才会被调用,而用空值调用setter会导致漏洞。如果不指定表达式,setter 可能不会被调用?【参考方案3】:我认为url=""
有效,因为url
属性在spring-security XSD 中属于xs:token
类型,并且空字符串转换为null
(xs:token
正在删除任何前导或尾随空格,所以@987654328 @ 可以被识别为没有值)。也许$ldap.server.url
的值被解析为空字符串,这就是你遇到错误的原因。
您可以尝试使用 Spring 配置文件来定义 ldap 服务器的不同配置(有关配置文件的详细信息,请参阅Spring Team Blog)
【讨论】:
LdapServerBeanDefinitionParser 已经在处理它了。不知何故,它设法在构造函数中创建了带有空白 URL 的 org.springframework.security.ldap.DefaultSpringSecurityContextSource 的 bean 定义,即使所有检查似乎都已到位。 我想我已经找到了为什么 Ritesh 正确以及为什么它不运行:当我调试服务器的启动时(在 LdapServerBeanDefinition 的方法解析中),所有占位符都没有被替换。所以 url 是:$ldap.server.url。占位符的解析是在上下文源创建后完成的。 根据文档static.springsource.org/spring-security/site/docs/3.1.x/…,如果我们要创建嵌入式服务器,则根本不应该使用 url 属性。【参考方案4】:我认为在使用占位符时存在问题。以下最有可能解决问题:
创建一个扩展 PropertyPlaceHolderConfigurer 的类并覆盖其方法 convertPropertyValue() 在该方法中,如果您发现除了 LDAP url 类型的字符串以外的任何其他内容,即 ldap://myldapserver.com/dc=springframeworg,dc=org
您还需要在上下文文件中配置类 PropertyPlaceHolderConfigurer 的新特化。
希望这会有所帮助。
【讨论】:
【参考方案5】:你可以在application.properties
文件中定义空的String
如下:
com.core.estimation.stopwords=\ \
【讨论】:
以上是关于弹簧,属性文件,空值的主要内容,如果未能解决你的问题,请参考以下文章