fix: Prevent NPE during BearerTokenAuth import (#40688)

This commit is contained in:
Nilansh Bansal 2025-05-19 17:39:26 +05:30 committed by GitHub
parent 5a3ae4e059
commit bddf6063e2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 242 additions and 3 deletions

View File

@ -364,11 +364,17 @@ public class DatasourceImportableServiceCEImpl implements ImportableServiceCE<Da
} }
if (StringUtils.equals(authType, DBAuth.class.getName())) { if (StringUtils.equals(authType, DBAuth.class.getName())) {
final DBAuth dbAuth = decryptedFields.getDbAuth(); DBAuth dbAuth = decryptedFields.getDbAuth();
if (dbAuth == null) {
dbAuth = new DBAuth();
}
dbAuth.setPassword(decryptedFields.getPassword()); dbAuth.setPassword(decryptedFields.getPassword());
datasourceStorage.getDatasourceConfiguration().setAuthentication(dbAuth); datasourceStorage.getDatasourceConfiguration().setAuthentication(dbAuth);
} else if (StringUtils.equals(authType, BasicAuth.class.getName())) { } else if (StringUtils.equals(authType, BasicAuth.class.getName())) {
final BasicAuth basicAuth = decryptedFields.getBasicAuth(); BasicAuth basicAuth = decryptedFields.getBasicAuth();
if (basicAuth == null) {
basicAuth = new BasicAuth();
}
basicAuth.setPassword(decryptedFields.getPassword()); basicAuth.setPassword(decryptedFields.getPassword());
datasourceStorage.getDatasourceConfiguration().setAuthentication(basicAuth); datasourceStorage.getDatasourceConfiguration().setAuthentication(basicAuth);
} else if (StringUtils.equals(authType, OAuth2.class.getName())) { } else if (StringUtils.equals(authType, OAuth2.class.getName())) {
@ -383,7 +389,10 @@ public class DatasourceImportableServiceCEImpl implements ImportableServiceCE<Da
datasourceStorage.getDatasourceConfiguration().setAuthentication(auth2); datasourceStorage.getDatasourceConfiguration().setAuthentication(auth2);
} else if (StringUtils.equals(authType, BearerTokenAuth.class.getName())) { } else if (StringUtils.equals(authType, BearerTokenAuth.class.getName())) {
BearerTokenAuth auth = new BearerTokenAuth(); BearerTokenAuth auth = new BearerTokenAuth();
auth.setBearerToken(decryptedFields.getBearerTokenAuth().getBearerToken()); BearerTokenAuth decryptedBearerTokenAuth = decryptedFields.getBearerTokenAuth();
if (decryptedBearerTokenAuth != null) {
auth.setBearerToken(decryptedBearerTokenAuth.getBearerToken());
}
datasourceStorage.getDatasourceConfiguration().setAuthentication(auth); datasourceStorage.getDatasourceConfiguration().setAuthentication(auth);
} }
} }

View File

@ -0,0 +1,230 @@
package com.appsmith.server.datasources.importable;
import com.appsmith.external.models.AuthenticationDTO;
import com.appsmith.external.models.BasicAuth;
import com.appsmith.external.models.BearerTokenAuth;
import com.appsmith.external.models.DBAuth;
import com.appsmith.external.models.DatasourceConfiguration;
import com.appsmith.external.models.DatasourceStorage;
import com.appsmith.external.models.DecryptedSensitiveFields;
import com.appsmith.external.models.OAuth2;
import com.appsmith.server.datasources.base.DatasourceService;
import com.appsmith.server.services.SequenceService;
import com.appsmith.server.services.WorkspaceService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.lang.reflect.Method;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
@ExtendWith(MockitoExtension.class)
class DatasourceImportableServiceCEImplTest { // Renamed class to match convention
@Mock
DatasourceService datasourceService;
@Mock
WorkspaceService workspaceService;
@Mock
SequenceService sequenceService;
DatasourceImportableServiceCEImpl importService;
@BeforeEach
void setUp() {
importService = new DatasourceImportableServiceCEImpl(datasourceService, workspaceService, sequenceService);
}
// Helper to call the private method using reflection
private void callUpdateAuthenticationDTOWithReflection(
DatasourceStorage datasourceStorage, DecryptedSensitiveFields decryptedFields) {
try {
Method method = DatasourceImportableServiceCEImpl.class.getDeclaredMethod(
"updateAuthenticationDTO", DatasourceStorage.class, DecryptedSensitiveFields.class);
method.setAccessible(true);
method.invoke(importService, datasourceStorage, decryptedFields);
} catch (Exception e) {
fail("Failed to invoke updateAuthenticationDTO via reflection", e);
}
}
@Test
void updateAuthenticationDTO_WhenAuthTypeIsBearer_AndDecryptedTokenIsValid_ShouldSetBearerTokenAuth() {
DatasourceStorage storage = new DatasourceStorage();
DatasourceConfiguration dsConfig = new DatasourceConfiguration();
storage.setDatasourceConfiguration(dsConfig);
DecryptedSensitiveFields decryptedFields = new DecryptedSensitiveFields();
decryptedFields.setAuthType(BearerTokenAuth.class.getName());
BearerTokenAuth tokenDetails = new BearerTokenAuth();
tokenDetails.setBearerToken("test-bearer-token");
decryptedFields.setBearerTokenAuth(tokenDetails);
callUpdateAuthenticationDTOWithReflection(storage, decryptedFields);
AuthenticationDTO authResult = dsConfig.getAuthentication();
assertNotNull(authResult, "Authentication result should not be null");
assertTrue(authResult instanceof BearerTokenAuth, "Authentication should be BearerTokenAuth");
assertEquals("test-bearer-token", ((BearerTokenAuth) authResult).getBearerToken());
}
@Test
void
updateAuthenticationDTO_WhenAuthTypeIsBearer_AndDecryptedBearerTokenAuthIsNull_ShouldSetBearerAuthWithNullToken() {
DatasourceStorage storage = new DatasourceStorage();
DatasourceConfiguration dsConfig = new DatasourceConfiguration();
storage.setDatasourceConfiguration(dsConfig);
DecryptedSensitiveFields decryptedFields = new DecryptedSensitiveFields();
decryptedFields.setAuthType(BearerTokenAuth.class.getName());
decryptedFields.setBearerTokenAuth(null); // Key condition for the fix
callUpdateAuthenticationDTOWithReflection(storage, decryptedFields);
AuthenticationDTO authResult = dsConfig.getAuthentication();
assertNotNull(authResult, "Authentication result should not be null");
assertTrue(authResult instanceof BearerTokenAuth, "Authentication should be BearerTokenAuth");
assertNull(((BearerTokenAuth) authResult).getBearerToken(), "Bearer token should be null");
}
@Test
void updateAuthenticationDTO_WhenAuthTypeIsDbAuth_AndDbAuthDetailsArePresent_ShouldSetDbAuth() {
DatasourceStorage storage = new DatasourceStorage();
DatasourceConfiguration dsConfig = new DatasourceConfiguration();
storage.setDatasourceConfiguration(dsConfig);
DecryptedSensitiveFields decryptedFields = new DecryptedSensitiveFields();
decryptedFields.setAuthType(DBAuth.class.getName());
DBAuth dbAuthDetails = new DBAuth();
dbAuthDetails.setUsername("testuser");
decryptedFields.setPassword("testpassword"); // Password comes from top-level DecryptedSensitiveFields
decryptedFields.setDbAuth(dbAuthDetails);
callUpdateAuthenticationDTOWithReflection(storage, decryptedFields);
AuthenticationDTO authResult = dsConfig.getAuthentication();
assertNotNull(authResult, "Authentication result should not be null");
assertTrue(authResult instanceof DBAuth, "Authentication should be DBAuth");
assertEquals("testuser", ((DBAuth) authResult).getUsername());
assertEquals("testpassword", ((DBAuth) authResult).getPassword());
}
@Test
void updateAuthenticationDTO_WhenAuthTypeIsDbAuth_AndDecryptedDbAuthIsNull_ShouldSetDbAuthWithPasswordOnly() {
DatasourceStorage storage = new DatasourceStorage();
DatasourceConfiguration dsConfig = new DatasourceConfiguration();
storage.setDatasourceConfiguration(dsConfig);
DecryptedSensitiveFields decryptedFields = new DecryptedSensitiveFields();
decryptedFields.setAuthType(DBAuth.class.getName());
decryptedFields.setDbAuth(null); // Decrypted DBAuth object within DecryptedSensitiveFields is null
decryptedFields.setPassword("only-password");
callUpdateAuthenticationDTOWithReflection(storage, decryptedFields);
AuthenticationDTO authResult = dsConfig.getAuthentication();
assertNotNull(authResult, "Authentication result should not be null");
// The actual method creates a new DBAuth if decryptedFields.getDbAuth() is null.
// And then sets the password on it.
assertTrue(authResult instanceof DBAuth, "Authentication should be DBAuth");
assertNull(
((DBAuth) authResult).getUsername(), "Username should be null as the provided DBAuth object was null");
assertEquals("only-password", ((DBAuth) authResult).getPassword(), "Password should be set");
}
@Test
void updateAuthenticationDTO_WhenAuthTypeIsBasicAuth_AndBasicAuthDetailsArePresent_ShouldSetBasicAuth() {
DatasourceStorage storage = new DatasourceStorage();
DatasourceConfiguration dsConfig = new DatasourceConfiguration();
storage.setDatasourceConfiguration(dsConfig);
DecryptedSensitiveFields decryptedFields = new DecryptedSensitiveFields();
decryptedFields.setAuthType(BasicAuth.class.getName());
BasicAuth basicAuthDetails = new BasicAuth();
basicAuthDetails.setUsername("basicuser");
decryptedFields.setPassword("basicpassword");
decryptedFields.setBasicAuth(basicAuthDetails);
callUpdateAuthenticationDTOWithReflection(storage, decryptedFields);
AuthenticationDTO authResult = dsConfig.getAuthentication();
assertNotNull(authResult);
assertTrue(authResult instanceof BasicAuth);
assertEquals("basicuser", ((BasicAuth) authResult).getUsername());
assertEquals("basicpassword", ((BasicAuth) authResult).getPassword());
}
@Test
void updateAuthenticationDTO_WhenAuthTypeIsOAuth2_AndOAuth2DetailsArePresent_ShouldSetOAuth2() {
// This is a simplified test for OAuth2 as it has more complex internal state (AuthenticationResponse)
// The main goal is to ensure the OAuth2 block is entered and an OAuth2 object is set.
DatasourceStorage storage = new DatasourceStorage();
DatasourceConfiguration dsConfig = new DatasourceConfiguration();
storage.setDatasourceConfiguration(dsConfig);
DecryptedSensitiveFields decryptedFields = new DecryptedSensitiveFields();
decryptedFields.setAuthType(OAuth2.class.getName());
OAuth2 oauth2Details = new OAuth2();
oauth2Details.setClientId("test-client-id");
// For OAuth2, password from decryptedFields is typically clientSecret
decryptedFields.setPassword("test-client-secret");
decryptedFields.setOpenAuth2(oauth2Details);
// Other OAuth2 fields like token, refreshToken, tokenResponse would be set on `authResponse`
// inside the actual method. For this test, we mainly check if OAuth2 is set.
decryptedFields.setToken("sample-token");
decryptedFields.setRefreshToken("sample-refresh-token");
callUpdateAuthenticationDTOWithReflection(storage, decryptedFields);
AuthenticationDTO authResult = dsConfig.getAuthentication();
assertNotNull(authResult);
assertTrue(authResult instanceof OAuth2);
assertEquals("test-client-id", ((OAuth2) authResult).getClientId());
// Verifying AuthenticationResponse part is more complex due to its instantiation inside the method
// For this test, verifying the type and one field is a good start.
assertNotNull(((OAuth2) authResult).getAuthenticationResponse());
assertEquals(
"sample-token",
((OAuth2) authResult).getAuthenticationResponse().getToken());
assertEquals(
"sample-refresh-token",
((OAuth2) authResult).getAuthenticationResponse().getRefreshToken());
assertEquals("test-client-secret", ((OAuth2) authResult).getClientSecret());
}
@Test
void updateAuthenticationDTO_WhenDsConfigIsNull_ShouldDoNothingAndNotThrow() {
DatasourceStorage storage = new DatasourceStorage();
storage.setDatasourceConfiguration(null); // dsConfig is null
DecryptedSensitiveFields decryptedFields = new DecryptedSensitiveFields();
decryptedFields.setAuthType(BearerTokenAuth.class.getName());
// Expect no exception
callUpdateAuthenticationDTOWithReflection(storage, decryptedFields);
assertNull(storage.getDatasourceConfiguration(), "DatasourceConfiguration should remain null");
}
@Test
void updateAuthenticationDTO_WhenAuthTypeIsNull_ShouldDoNothingAndNotSetAuth() {
DatasourceStorage storage = new DatasourceStorage();
DatasourceConfiguration dsConfig = new DatasourceConfiguration();
storage.setDatasourceConfiguration(dsConfig);
DecryptedSensitiveFields decryptedFields = new DecryptedSensitiveFields();
decryptedFields.setAuthType(null); // authType is null
callUpdateAuthenticationDTOWithReflection(storage, decryptedFields);
assertNull(dsConfig.getAuthentication(), "Authentication should not be set if authType is null");
}
}