2012-05-07 14 views
10

Ho configurato la sicurezza di primavera con un server LDAP (ma continua a leggere, non è un problema se non si ha conoscenza a riguardo, questo è davvero un problema di primavera). Tutto funziona come un fascino. Ecco la linea che uso per questo:Spring, file di proprietà, valori vuoti

<ldap-server ldif="" root="" manager-dn="" manager-password="" url="" id="ldapServer" /> 

Se riempio attributi LDIF e root, verrà eseguito un server embeded:

<ldap-server ldif="classpath://ldap.ldif" root="dc=springframework,dc=org" manager-dn="" manager-password="" url="" id="ldapServer" /> 

Se riempio altri campi, verrà eseguito un server remoto :

<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" /> 

Tutte queste cose funzionano correttamente. Ora voglio usare il meccanismo della molla per caricare tali parametri da un file di proprietà:

Così sostituisco valori degli attributi in questo modo:

<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" /> 

e creare un file di proprietà con:

ldap.server.url= 
ldap.server.manager.dn= 
ldap.server.manager.password= 

ldap.ldif.path= 
ldap.ldif.root= 

Ora , la parte divertente del problema. Se riempio le seguenti proprietà nel 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= 

Esegue un server remoto come previsto.

Se riempio il file di proprietà come questa:

ldap.server.url= 
ldap.server.manager.dn= 
ldap.server.manager.password= 

ldap.ldif.path= classpath:ldap.ldif 
ldap.ldif.root= dc=springframeworg,dc=org 

Esso non viene eseguito, lamentando che l'URL LDAP è mancante. Ma il problema è che se cambio la configurazione di primavera da:

<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" /> 

a (semplicemente rimuovendo il riferimento alla variabile $ {} 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" /> 

Funziona!

I miei pensieri sono che la molla non sostituisce il valore dell'attributo con la proprietà config one se questa è vuota. Ma lo trovo strano

Potete darmi qualche indizio per capirlo? E qual è la cosa migliore da fare per configurare il mio server LDAP tramite un file di proprietà?

EDIT: ciò è dovuto ad una scelta cattiva progettazione (guarda risposta accettata), un problema è stato aperto il jira: https://jira.springsource.org/browse/SEC-1966

+0

Quale versione di Primavera si usa? – Roadrunner

+0

Questo è il 3.0.5.RELEASE –

risposta

2

Ok, penso che questo sia un bug di sicurezza primaverile.

Se eseguo il debug e guardo la classe LdapServerBeanDefinition, esiste un metodo chiamato "parse". Ecco un estratto:

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); 
    } 

    ... 
} 

Se metto a punto qui, tutte le variabili (url, managerDn, managerPassword ...) non vengono sostituiti dal valore specificato nel file di proprietà. E così, url ha il valore $ {ldap.server.url}, managerDn ha il valore $ {ldap.server.manager.dn} e così via.

Il metodo parse crea un bean, un'origine di contesto che verrà utilizzata ulteriormente. E quando questo fagiolo sarà usato, i detentori di posto saranno sostituiti.

Qui abbiamo il bug. Il metodo di analisi controlla se l'URL è vuoto o no. Il problema è che l'URL non è vuoto qui perché ha il valore $ {ldap.server.url}. Quindi, il metodo parse crea una sorgente di contesto come un server remoto.

Quando verrà utilizzata l'origine creata, sostituirà $ {ldap.server.url} con un valore vuoto (come specificato nel file delle proprietà). E ....... Bug!

Non so davvero come risolvere questo per il momento, ma ora capisco il motivo per cui gli insetti;)

+0

Questo non è un bug. L'attributo url non deve essere utilizzato se si intende creare un server incorporato. Vedi http://static.springsource.org/spring-security/site/docs/3.1.x/reference/ldap.html#ldap-server – Ritesh

+0

Quello che io chiamo un bug è che usando una stringa vuota si esegue e usando una variabile non viene eseguito perché la sicurezza di primavera verifica che l'URL non sia vuoto non sostituendo la variabile con il suo valore (che può essere vuoto!). Questo è un design scadente. –

+1

In tal caso, penso che abbia senso segnalare un problema nel bug tracker di Spring, giusto? https://jira.springsource.org/secure/Dashboard.jspa –

1

non riesco a spiegarlo, ma penso che si può risolvere il problema utilizzando la sintassi predefinita, disponibile dalla primavera 3.0.0.RC1 (see).

Nella chageg registro si può leggere: PropertyPlaceholderConfigurer supporta "$ {myKey: myDefaultValue}" Sintassi inadempiente

In ogni caso, penso che il problema è dovuto al fatto "" è un valore valido, ma nessun valore nel file di proprietà non lo fanno.

+0

grazie per la risposta, ma ho sempre lo stesso bug usando il suggerimento del valore predefinito. –

+0

Non lo capisco. Se il valore predefinito è '' Penso che dovrebbe essere lo stesso che lo imposta a ''. – jddsantaella

+0

Sì, stavo anche pensando così ... È molto strano ... Forse, il setter di url viene chiamato solo quando usiamo un'espressione di molla, e chiamare il setter con un valore vuoto causa l'errore. Nel caso in cui non si specifichi l'espressione, il setter non viene forse chiamato? –

1

ritengo che url="" funziona perché attributo url è di tipo xs:token in XSD molla sicurezza e la stringa vuota viene convertita in null (xs:token è la rimozione spazi iniziali o finali, così "" può essere riconosciuto alcun valore). Forse il valore di ${ldap.server.url} è stato risolto come stringa vuota ed è per questo che hai un errore.

È possibile provare i profili uso di primavera per definire diverse configurazioni di server LDAP (vedi Spring Team Blog per i dettagli su profili)

+1

LdapServerBeanDefinitionParser si sta già occupando di esso. In qualche modo è riuscito a creare la definizione di bean di org.springframework.security.ldap.DefaultSpringSecurityContextSource con URL vuoto nel costruttore anche se sembra che tutti i controlli siano in atto per impedirlo. – Ritesh

+1

Penso di aver trovato il motivo per cui Ritesh ha ragione e perché non viene eseguito: quando eseguo il debug del server (nel metodo parse di LdapServerBeanDefinition), tutti i segnaposti non vengono sostituiti. Quindi url è: $ {ldap.server.url}. La risoluzione del segnaposto viene eseguita dopo la creazione della sorgente di contesto. –

+0

Come da documentazione http://static.springsource.org/spring-security/site/docs/3.1.x/reference/ldap.html#ldap-server, l'attributo url non dovrebbe essere usato affatto se vogliamo creare un server incorporato. – Ritesh

1

Credo che ci sia un problema qui durante l'utilizzo di segnaposto. Di seguito sarà molto probabilmente risolvere il problema:

Creare una classe che si estende PropertyPlaceholderConfigurer e sovrascrivere il metodo convertPropertyValue() nel metodo è possibile restituire la proprietà come stringa vuota se trovate qualcosa di diverso da una stringa che è di tipo URL LDAP ie ldap: //myldapserver.com/dc=springframeworg,dc=org

Inoltre, è necessario configurare la nuova specializzazione della classe PropertyPlaceHolderConfigurer nel file di contesto.

Spero che questo aiuti.