Expected Behavior
OAuth2ClientPropertiesRegistrationAdapter.getBuilderFromIssuerIfPossible should validate that issuer is not blank
Because few lines after, code throws exception if this issuer is null or emptyString or blankString
Current Behavior
OAuth2ClientPropertiesRegistrationAdapter.getBuilderFromIssuerIfPossible validates that issuer is not null
Context
class OAuth2ClientPropertiesRegistrationAdapter {
...
private static Builder getBuilderFromIssuerIfPossible(...) {
...
if (issuer != null) { // this code performs only null check
Builder builder = ClientRegistrations.fromIssuerLocation(issuer).registrationId(registrationId);
return getBuilder(builder, provider);
}
...
}
...
}
public static ClientRegistration.Builder fromIssuerLocation(String issuer) {
Assert.hasText(issuer, "issuer cannot be empty"); // this code perform null check + String content check
...
}
Comment From: wilkinsona
Thanks for the suggestion, @bitxon. Can you provide a bit of background on this please? I'd like to understand how you came to have the property configured but with an empty value.
If we treat an empty string as we currently treat null, we'll silently ignore the issuer URI configuration and use the provider's issuer URI instead. It sounds like that's what you'd prefer to happen, but someone else may prefer the current failure. If they have been trying to set the issuer URI and have made a mistake that led to it having an empty value, silently ignoring it may make that mistake harder to spot.
Comment From: bitxon
If in application.yml we have following configuration
spring.security.oauth2.client:
provider:
keycloak:
issuerUri: ${oauthUrl}
authorization-uri: ${oauthUrl}/protocol/openid-connect/auth
token-uri: ${oauthUrl}/protocol/openid-connect/token
jwk-set-uri: ${oauthUrl}/protocol/openid-connect/certs
user-info-uri: ${oauthUrl}/protocol/openid-connect/userinfo
user-name-attribute: preferred_username
So we will not be able to unset issuerUri in application-test.yml without tricks. Because following configuration will be considered as value with empty string:
spring.security.oauth2.client:
provider:
keycloak:
issuerUri:
Comment From: wilkinsona
Thanks for the background. Have you considered switching things around so that your configuration that's in application.yml is profile-specific? You would then avoid activating this profile in situations where you're currently activating the test profile and would no longer need to unset the issuerUri property.
We'd like to make it easier to unset a configuration property. https://github.com/spring-projects/spring-boot/issues/24133 is covering (some of) that. This feels like another case where it would be useful. I am reluctant to implement a point-fix that changes the handling of an empty string in this specific case for the reasons explained above. I'll flag this one so that we can see what the rest of the team thinks.
Comment From: mbhave
Unless switching things around where the configuration which contains issuer-uri is only active in a certain profile doesn't work , I don't think we should implement a point-fix change. As Andy pointed out we might silently ignore the failure that someone might expect.
Comment From: spring-projects-issues
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Comment From: bitxon
Thanks for the background. Have you considered switching things around so that your configuration that's in
application.ymlis profile-specific? You would then avoid activating this profile in situations where you're currently activating thetestprofile and would no longer need to unset theissuerUriproperty.We'd like to make it easier to unset a configuration property. #24133 is covering (some of) that. This feels like another case where it would be useful. I am reluctant to implement a point-fix that changes the handling of an empty string in this specific case for the reasons explained above. I'll flag this one so that we can see what the rest of the team thinks.
This approach is working fine:
application.yml
spring.security.oauth2.client:
provider:
keycloak:
#issuerUri is not specified here
authorization-uri: ${oauthUrl}/protocol/openid-connect/auth
token-uri: ${oauthUrl}/protocol/openid-connect/token
jwk-set-uri: ${oauthUrl}/protocol/openid-connect/certs
user-info-uri: ${oauthUrl}/protocol/openid-connect/userinfo
user-name-attribute: preferred_username
application-test.yml
oauthUrl: my-test-url
spring.security.oauth2.client:
provider:
keycloak:
issuerUri: ${oauthUrl}
application-dev.yml
oauthUrl: my-dev-url
spring.security.oauth2.client:
provider:
keycloak:
issuerUri: ${oauthUrl}
I just wanted to emphasize that for now we have switch-on(set uri) mechanism and miss switch-off mechanism(unset uri).
Comment From: wilkinsona
Thanks for following up, @bitxon. As mentioned above, #24133 is for making it possible to unset a property. We'll leave the handling of the issuer URI as it is for now for the reasons already discussed.
Comment From: falk-stefan
I am facing the same issues atm as I am trying to come up with a proper config-setup for different environments.
It's great that we can combine different configurations but it would be great if it was possible to null certain values sometimes.
For example, locally I am working with a PostgreSQL database, but the deployment uses a Cloud SQL. For this I'd need to different files application-pglocal.yaml and application-pgcloud.yaml.
It would be nice if we could write a application-pg.yaml which worked for both. For that it would be necessary to be able to set environment-variables to null if they are empty.
I don't know how this could be done though. Maybe if the syntax for environment variables would be extended:
${VARIABLE:} # Will be empty-string if not set
${VARIABLE:default-value} # Will never be null
${VARIABLE:default-value:true} # Will be null if set to empty-string
${VARIABLE::true} # Will be null if not set
${VARIABLE::false} # Will be empty-string if not set
Then we could do something like this:
spring:
cloud:
gcp:
sql:
database-name: ${DB_NAME::true}
instance-connection-name: ${DB_CONNECTION_NAME::true}
datasource:
driver-class-name: org.postgresql.Driver
password: ${JDBC_DATABASE_PASSWORD:postgres}
username: ${JDBC_DATABASE_USERNAME:root}
A more pragmative solution would probably be to set any empty-string to null per default but I'm not sure how many fires this would turn on.
Comment From: wilkinsona
@falk-stefan Support for setting a property back to null is being tracked by the previously mentioned https://github.com/spring-projects/spring-boot/issues/24133.