11package com .dbschema .mongo ;
22
3+ import com .dbschema .mongo .oidc .OidcCallback ;
34import com .mongodb .ConnectionString ;
45import com .mongodb .MongoClientSettings ;
6+ import com .mongodb .MongoCredential ;
7+ import com .mongodb .ServerApi ;
8+ import com .mongodb .ServerApiVersion ;
59import com .mongodb .client .MongoClient ;
610import com .mongodb .client .MongoClients ;
711import com .mongodb .client .MongoDatabase ;
@@ -26,79 +30,103 @@ public class MongoClientWrapper implements AutoCloseable {
2630 private boolean isClosed = false ;
2731 private final MongoClient mongoClient ;
2832 public final String databaseNameFromUrl ;
33+ public final OidcCallback oidcCallback ;
2934
30- public MongoClientWrapper (@ NotNull String uri , @ NotNull Properties prop , @ Nullable String username , @ Nullable String password ) throws SQLException {
35+ public MongoClientWrapper (@ NotNull String uri , @ NotNull Properties prop , @ Nullable String username , @ Nullable String password , @ Nullable MongoCredential .OidcCallbackContext callbackContext ) throws SQLException {
36+ this .oidcCallback = new OidcCallback (callbackContext );
3137 try {
32- boolean automaticEncoding = ENCODE_CREDENTIALS_DEFAULT ;
33- if (prop .getProperty (ENCODE_CREDENTIALS ) != null ) {
34- automaticEncoding = Boolean .parseBoolean (prop .getProperty (ENCODE_CREDENTIALS ));
35- }
38+ boolean automaticEncoding = ENCODE_CREDENTIALS_DEFAULT ;
39+ if (prop .getProperty (ENCODE_CREDENTIALS ) != null ) {
40+ automaticEncoding = Boolean .parseBoolean (prop .getProperty (ENCODE_CREDENTIALS ));
41+ }
3642
37- uri = insertCredentials (uri , username , password , automaticEncoding );
38- uri = insertAuthMechanism (uri , prop .getProperty (AUTH_MECHANISM ));
39- uri = insertAuthSource (uri , prop .getProperty (AUTH_SOURCE ));
40- uri = insertAuthProperty (uri , AWS_SESSION_TOKEN , prop .getProperty (AWS_SESSION_TOKEN ));
41- uri = insertAuthProperty (uri , SERVICE_NAME , prop .getProperty (SERVICE_NAME ));
42- uri = insertAuthProperty (uri , SERVICE_REALM , prop .getProperty (SERVICE_REALM ));
43- String canonicalizeHostName = prop .getProperty (CANONICALIZE_HOST_NAME );
44- if (Boolean .TRUE .toString ().equalsIgnoreCase (canonicalizeHostName ) || Boolean .FALSE .toString ().equalsIgnoreCase (canonicalizeHostName )) {
45- uri = insertAuthProperty (uri , CANONICALIZE_HOST_NAME , canonicalizeHostName );
46- }
47- else if (canonicalizeHostName != null ) {
48- System .err .println ("Unknown " + CANONICALIZE_HOST_NAME + " value. Must be true or false." );
49- }
50- uri = insertRetryWrites (uri , prop .getProperty (RETRY_WRITES ));
43+ uri = insertCredentials (uri , username , password , automaticEncoding );
44+ uri = insertAuthMechanism (uri , prop .getProperty (AUTH_MECHANISM ));
45+ uri = insertAuthSource (uri , prop .getProperty (AUTH_SOURCE ));
46+ uri = insertAuthProperty (uri , AWS_SESSION_TOKEN , prop .getProperty (AWS_SESSION_TOKEN ));
47+ uri = insertAuthProperty (uri , SERVICE_NAME , prop .getProperty (SERVICE_NAME ));
48+ uri = insertAuthProperty (uri , SERVICE_REALM , prop .getProperty (SERVICE_REALM ));
49+ String canonicalizeHostName = prop .getProperty (CANONICALIZE_HOST_NAME );
50+ if (Boolean .TRUE .toString ().equalsIgnoreCase (canonicalizeHostName ) || Boolean .FALSE .toString ().equalsIgnoreCase (canonicalizeHostName )) {
51+ uri = insertAuthProperty (uri , CANONICALIZE_HOST_NAME , canonicalizeHostName );
52+ }
53+ else if (canonicalizeHostName != null ) {
54+ System .err .println ("Unknown " + CANONICALIZE_HOST_NAME + " value. Must be true or false." );
55+ }
56+ uri = insertRetryWrites (uri , prop .getProperty (RETRY_WRITES ));
57+
58+
59+ // Construct a ServerApi instance using the ServerApi.builder() method
60+ ServerApi serverApi = ServerApi .builder ()
61+ .version (ServerApiVersion .V1 )
62+ .build ();
5163
5264 ConnectionString connectionString = new ConnectionString (uri );
53- databaseNameFromUrl = connectionString .getDatabase ();
54- int maxPoolSize = getMaxPoolSize (prop );
55- MongoClientSettings .Builder builder = MongoClientSettings .builder ()
56- .applyConnectionString (connectionString )
57- .applyToConnectionPoolSettings (b -> b .maxSize (maxPoolSize ));
58- String application = prop .getProperty (APPLICATION_NAME );
59- if (!isNullOrEmpty (application )) {
60- builder .applicationName (application );
61- }
62- if ("true" .equals (prop .getProperty ("ssl" ))) {
63- boolean allowInvalidCertificates = uri .contains ("tlsAllowInvalidCertificates=true" ) || uri .contains ("sslAllowInvalidCertificates=true" )
64- || isTrue (prop .getProperty (ALLOW_INVALID_CERTIFICATES , Boolean .toString (ALLOW_INVALID_CERTIFICATES_DEFAULT )));
65- builder .applyToSslSettings (s -> {
66- s .enabled (true );
67- boolean allowInvalidHostnames = isTrue (prop .getProperty (ALLOW_INVALID_HOSTNAMES , Boolean .toString (ALLOW_INVALID_HOSTNAMES_DEFAULT )));
68- if (allowInvalidHostnames ) s .invalidHostNameAllowed (true );
69- if (allowInvalidCertificates ) {
70- String keyStoreType = System .getProperty ("javax.net.ssl.keyStoreType" , KeyStore .getDefaultType ());
71- String keyStorePassword = System .getProperty ("javax.net.ssl.keyStorePassword" , "" );
72- String keyStoreUrl = System .getProperty ("javax.net.ssl.keyStore" , "" );
73- // check keyStoreUrl
74- if (!isNullOrEmpty (keyStoreUrl )) {
75- try {
76- new URL (keyStoreUrl );
77- } catch (MalformedURLException e ) {
78- keyStoreUrl = "file:" + keyStoreUrl ;
79- }
80- }
81- try {
82- s .context (getTrustEverybodySSLContext (keyStoreUrl , keyStoreType , keyStorePassword ));
83- }
84- catch (SSLUtil .SSLParamsException e ) {
85- throw new RuntimeException (e );
86- }
87- }
88- });
89- }
90- if (connectionString .getUuidRepresentation () == null ) {
91- String uuidRepresentation = prop .getProperty (UUID_REPRESENTATION , UUID_REPRESENTATION_DEFAULT );
92- builder .uuidRepresentation (createUuidRepresentation (uuidRepresentation ));
93- }
94- if (connectionString .getServerSelectionTimeout () == null ) {
95- int timeout = Integer .parseInt (prop .getProperty (SERVER_SELECTION_TIMEOUT , SERVER_SELECTION_TIMEOUT_DEFAULT ));
96- builder .applyToClusterSettings (b -> b .serverSelectionTimeout (timeout , TimeUnit .MILLISECONDS ));
97- }
98- if (connectionString .getConnectTimeout () == null ) {
99- int timeout = Integer .parseInt (prop .getProperty (CONNECT_TIMEOUT , CONNECT_TIMEOUT_DEFAULT ));
100- builder .applyToSocketSettings (b -> b .connectTimeout (timeout , TimeUnit .MILLISECONDS ));
101- }
65+
66+ MongoCredential credential ;
67+
68+ credential =
69+ MongoCredential .createOidcCredential (
70+ connectionString .getUsername ())
71+ .withMechanismProperty (
72+ MongoCredential .OIDC_HUMAN_CALLBACK_KEY , oidcCallback );
73+
74+
75+ databaseNameFromUrl = connectionString .getDatabase ();
76+ MongoClientSettings .Builder builder = MongoClientSettings .builder ()
77+ .applyConnectionString (connectionString )
78+ .serverApi (serverApi )
79+ .credential (credential )
80+ .uuidRepresentation (createUuidRepresentation (prop .getProperty (UUID_REPRESENTATION , UUID_REPRESENTATION_DEFAULT )))
81+ .applyToConnectionPoolSettings (b -> b .maxSize (getMaxPoolSize (prop )))
82+
83+ .applyToSocketSettings (b -> b .connectTimeout (Integer .parseInt (prop .getProperty (CONNECT_TIMEOUT , CONNECT_TIMEOUT_DEFAULT )), TimeUnit .MILLISECONDS ));
84+
85+ String application = prop .getProperty (APPLICATION_NAME );
86+ if (!isNullOrEmpty (application )) {
87+ builder .applicationName (application );
88+ }
89+ if ("true" .equals (prop .getProperty ("ssl" ))) {
90+ boolean allowInvalidCertificates = uri .contains ("tlsAllowInvalidCertificates=true" ) || uri .contains ("sslAllowInvalidCertificates=true" )
91+ || isTrue (prop .getProperty (ALLOW_INVALID_CERTIFICATES , Boolean .toString (ALLOW_INVALID_CERTIFICATES_DEFAULT )));
92+ builder .applyToSslSettings (s -> {
93+ s .enabled (true );
94+ boolean allowInvalidHostnames = isTrue (prop .getProperty (ALLOW_INVALID_HOSTNAMES , Boolean .toString (ALLOW_INVALID_HOSTNAMES_DEFAULT )));
95+ if (allowInvalidHostnames ) s .invalidHostNameAllowed (true );
96+ if (allowInvalidCertificates ) {
97+ String keyStoreType = System .getProperty ("javax.net.ssl.keyStoreType" , KeyStore .getDefaultType ());
98+ String keyStorePassword = System .getProperty ("javax.net.ssl.keyStorePassword" , "" );
99+ String keyStoreUrl = System .getProperty ("javax.net.ssl.keyStore" , "" );
100+ // check keyStoreUrl
101+ if (!isNullOrEmpty (keyStoreUrl )) {
102+ try {
103+ new URL (keyStoreUrl );
104+ } catch (MalformedURLException e ) {
105+ keyStoreUrl = "file:" + keyStoreUrl ;
106+ }
107+ }
108+ try {
109+ s .context (getTrustEverybodySSLContext (keyStoreUrl , keyStoreType , keyStorePassword ));
110+ }
111+ catch (SSLUtil .SSLParamsException e ) {
112+ throw new RuntimeException (e );
113+ }
114+ }
115+ });
116+ }
117+ if (connectionString .getUuidRepresentation () == null ) {
118+ String uuidRepresentation = prop .getProperty (UUID_REPRESENTATION , UUID_REPRESENTATION_DEFAULT );
119+ builder .uuidRepresentation (createUuidRepresentation (uuidRepresentation ));
120+ }
121+ if (connectionString .getServerSelectionTimeout () == null ) {
122+ int timeout = Integer .parseInt (prop .getProperty (SERVER_SELECTION_TIMEOUT , SERVER_SELECTION_TIMEOUT_DEFAULT ));
123+ builder .applyToClusterSettings (b -> b .serverSelectionTimeout (timeout , TimeUnit .MILLISECONDS ));
124+ }
125+ if (connectionString .getConnectTimeout () == null ) {
126+ int timeout = Integer .parseInt (prop .getProperty (CONNECT_TIMEOUT , CONNECT_TIMEOUT_DEFAULT ));
127+ builder .applyToSocketSettings (b -> b .connectTimeout (timeout , TimeUnit .MILLISECONDS ));
128+ }
129+
102130 this .mongoClient = MongoClients .create (builder .build ());
103131 }
104132 catch (Exception e ) {
@@ -160,6 +188,10 @@ public MongoDatabase getDatabase(String databaseName) throws SQLAlreadyClosedExc
160188 return mongoClient .getDatabase (databaseName );
161189 }
162190
191+ public OidcCallback getOidcCallback () {
192+ return this .oidcCallback ;
193+ }
194+
163195 @ NotNull
164196 public MongoClient getMongoClient () {
165197 return mongoClient ;
0 commit comments