jdaugherty opened a new issue, #16550:
URL: https://github.com/apache/grails-core/issues/16550
### Steps to Reproduce
In a Grails 8.1.x application (verified at b2b20a89e4 with Spring Boot
4.1.1), `grails-app/conf/application.yml`:
```yaml
grails:
cors:
enabled: true
allowedOrigins:
- https://grails.github.io
- "${CORS_ALLOWED_ORIGIN:https://start.grails.org}"
```
Start the application and look at the `GrailsCorsConfiguration` bean, which
is `@ConfigurationProperties(prefix = 'grails.cors')`. Any
`@ConfigurationProperties` bean with a `List<String>` property fed from a YAML
list behaves the same.
### Expected Behaviour
```groovy
allowedOrigins == ['https://grails.github.io', 'https://start.grails.org']
```
or the value of `CORS_ALLOWED_ORIGIN` when it is set: the placeholder is
resolved, as it is for a scalar property and as a Spring Boot application
resolves it from the same YAML.
### Actual Behaviour
```groovy
allowedOrigins == ['https://grails.github.io',
'${CORS_ALLOWED_ORIGIN:https://start.grails.org}']
```
The placeholder is bound as written, so the CORS filter never allows the
origin. Found while porting the Forge web application to Grails, where the
allowed origins are configured from environment variables this way.
### Cause
`org.grails.config.NavigableMapPropertySource` presents a YAML list of
scalars as one property whose value is the `List`. Spring Boot's `Binder`
resolves placeholders only in a `String` value:
`PropertySourcesPlaceholdersResolver.resolvePlaceholders` returns any other
value untouched, and `IndexedElementsBinder` calls it on the whole-collection
value before converting it, so the elements are copied as they are. Spring
Boot's own YAML loader never produces a whole-list property; it presents
`allowedOrigins[0]`, `allowedOrigins[1]`, … and the binder binds, and resolves,
each element on its own.
Since 12c05b5ce2, 379baff716 and b56b3f5226 (8.0.x and later)
`NavigableMapPropertySource` presents a list *of objects* under those indexed
names, so such a list binds correctly. A list of scalars, for which
`isObjectList` is false, is still presented whole. `YamlPropertySourceLoader`
is the same on 7.0.x, where no list is presented that way.
Grails' own `Config` is not affected:
`PropertySourcesConfig.processAndEvaluate` resolves the placeholders of list
elements itself, but the Boot binder reads the property source, not the
`Config`.
### Workarounds
- Declare the list as one comma separated scalar; the binder resolves the
string and splits it:
```yaml
allowedOrigins:
"https://grails.github.io,${CORS_ALLOWED_ORIGIN:https://start.grails.org}"
```
- A `BeanPostProcessor` that passes the bound values through
`Environment.resolvePlaceholders`.
### Suggested Fix
Present a list of scalars under indexed names in
`NavigableMapPropertySource` as well, as a list of objects already is, so that
Spring Boot binds and resolves each element. `getNavigableProperty` and the
Grails `Config` would keep returning the `List`.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]