Up to Spring Boot 2.3.8, we used H2 as a stand in for our Oracle DB in local development. When needing to look into the tables, we used /h2-console, without any problems.
This is no longer working starting with 2.4.x. Every attempt to log in fails with "Wrong userid or password 280000-200".
If tried back and forth a bit, tried to debug, but so far no luck, the only difference obvious to me being the Spring Boot version.
I cross checked by using the command line shell of H2, and there is exactly the same problem: Login succeeds for a database, that was created by a 2.3.x service, but fails for a 2.4.x service. I switched sequence, by deleting the database, and recreating it using the H2 shell, which forces the user to specify the new password - with the result I already suspected: in this case the server startup fails for the 2.4.x service, because now the service can not connect to the database.
My impression is, that the password somehow gets garbled in unpredictable, but consistent way, when Spring Boot passes it to H2.
It doesn't matter, whether I go with the default admin user "sa"/"" (empty password), or force my own password, e,g. "sa"/"sa".
Are there any debug switches that may highlight, what happens to the password? Or any smart location for a break point to set?
Regards, Thomas
Comment From: wilkinsona
Have you checked the 2.4 release notes and, in particular, this section? Please let us know if that helps. If not, please provide a minimal sample that reproduces the problem and we can take another look.
Comment From: gtsh
Ok, tried to add spring.datasource.initialization-mode: ALWAYS, since I already had username=sa.
Anyway, the initilization-mode was probably not the problem, as the database gets started and successfully accessed by liquibase during startup in surefire and failsafe test, as well as when doing a spring-boot:run. I'm actually seeing lines
08:23:14.830 [restartedMain] INFO [-] o.s.b.autoconfigure.h2.H2ConsoleAutoConfiguration - H2 console available at '/h2-console'. Database available at 'jdbc:h2:./foobardb'
08:23:15.211 [restartedMain] INFO [-] liquibase.lockservice - Changelog-Protokoll erfolgreich gesperrt.
08:23:15.463 [restartedMain] INFO [-] liquibase.changelog - Creating database history table with name: PUBLIC.DATABASECHANGELOG
which confirm this.
I also should mention, that in the code, the datasource properties are relocated:
@Configuration
public class DatabaseConfiguration {
@Bean
@Primary
@ConfigurationProperties("app.datasource.foobar")
public DataSourceProperties szenarienDataSourceProperties() {
return new DataSourceProperties();
}
which is reflected in the configuration, which, after some experiments now looks like this:
app:
datasource:
foobar:
url: jdbc:h2:./foobardb;AUTO_SERVER=TRUE;AUTO_SERVER_PORT=18084;MODE=Oracle;DB_CLOSE_DELAY=-1
username: sa <-- was already present
password: sa <-- added this, in oder to test whether the password beeing empty (""? or null?) might have been a problem
driver-class-name: org.h2.Driver
type: org.h2.jdbcx.JdbcDataSource
initialization-mode: always <-- added this on your request as per documentation
spring:
datasource: <-- for good measure, also added this, just in case, but no joy there too.
username: sa
password: sa
initialization-mode: always
So I'm going now to strip the project of all the things I'm not allowed to disclose, while also simplfying it (we use custom pom inheritance), which might take a moment.
Comment From: gtsh
Above ZIP contains a small Spring Boot Service, that on a
mvn clean spring-boot:run
will create a h2 database 'myh2db' in its directory, allowing accces using the h2 web console at http://localhost:8080/h2-console with user/password sa/sa - if and only if your spring-boot-parent is a 2.3.x -Version.
Changing the Version to 2.4.0 or above will still bring up the web console, but login fails.
For the sake of an experiment, you may also switch the version, then do a mvn spring-boot:run (without clean!). This will attempt to login into the existing database, and will again fail with a login failure, if it was created with the other version configured as a parent.
Looks as if something weired is happening to the password on its way to the h2 database.
Comment From: snicoll
Thank you for the sample @gtsh
H2 has a setUser
method (and, typically, doesn't have a setUsername
method) so we should have an alias for that. It does not work because the binder no longer set the configured user.
We've refactored how those aliases are registered and this may have introduced a regression in that area.
Comment From: snicoll
It's not really regression strictly speaking. The sample "forces" the datasource to be org.h2.jdbcx.JdbcDataSource
and Spring Boot does not support this datasource (per the reference guide).
The regression comes from the fact that the user
-> username
alias was applied previously regardless of the database type and we're now more selective.
@gtsh can you share why you're forcing the type there? Neither app.datasource.myh2db.type
nor app.datasource.myh2db.driver-class-name
are necessary given that initializeDataSourceBuilder
is going to take care of that for you and use a connection pool / driver that's suitable based on your classpath.
Comment From: snicoll
I've also created https://github.com/spring-projects/spring-boot/issues/25333 to make it clearer in the doc what DataSourceProperties#intializeDataSourceBuilder
supports.
Comment From: gtsh
@gtsh can you share why you're forcing the type there? Neither
app.datasource.myh2db.type
norapp.datasource.myh2db.driver-class-name
are necessary given thatinitializeDataSourceBuilder
is going to take care of that for you and use a connection pool / driver that's suitable based on your classpath.
Forcing driver & datasource is what I've seen on next to every installation I have come across so far, whether it was Spring Boot or other (JEE DDs for that matter). Also, wanting to use Oracle UCP for production, I haven't much use for Hikari or C3P0, so I culled those from the classpath in order to shrink the distributable as well as to keep the classpath clean. This left me with the H2-datasource as the only option for local development, and forcing it seemed sensible also, because the Oracle DS has been configured as default. So you may say, I didn't knew better.
Anyway, many thanks for your prompt effort, I just managed to test it with 2.4.3, so this is working now as intended