弹簧,属性文件,空值

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 类型,并且空字符串转换为nullxs: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=\ \

【讨论】:

以上是关于弹簧,属性文件,空值的主要内容,如果未能解决你的问题,请参考以下文章

那些年我们踩过的坑,SQL 中的空值陷阱!

go数组

那些年我们踩过的坑,SQL 中的空值陷阱!

pandas 怎么处理表格中的空值

主键约束,外键约束,空值约束,默认值约束,唯一约束,检查约束的各个作用是啥?

MS ACCESS 2016 - 使用 Null 进行查询的标准