|
20 | 20 | import com.cloud.api.ApiResponseHelper; |
21 | 21 | import com.cloud.dc.dao.DataCenterDao; |
22 | 22 | import com.cloud.domain.dao.DomainDao; |
| 23 | +import com.cloud.exception.InvalidParameterValueException; |
| 24 | +import com.cloud.user.Account; |
23 | 25 | import com.cloud.user.AccountManager; |
24 | 26 | import com.cloud.user.dao.AccountDao; |
| 27 | +import org.apache.cloudstack.api.command.user.kms.hsm.DeleteHSMProfileCmd; |
25 | 28 | import org.apache.cloudstack.api.response.HSMProfileResponse; |
| 29 | +import org.apache.cloudstack.context.CallContext; |
| 30 | +import org.apache.cloudstack.framework.kms.KMSProvider; |
26 | 31 | import org.apache.cloudstack.kms.dao.HSMProfileDao; |
27 | 32 | import org.apache.cloudstack.kms.dao.HSMProfileDetailsDao; |
| 33 | +import org.apache.cloudstack.kms.dao.KMSKekVersionDao; |
| 34 | +import org.apache.cloudstack.kms.dao.KMSKeyDao; |
| 35 | +import org.apache.cloudstack.kms.dao.KMSWrappedKeyDao; |
28 | 36 | import org.junit.Test; |
29 | 37 | import org.junit.runner.RunWith; |
30 | 38 | import org.mockito.InjectMocks; |
|
35 | 43 | import org.mockito.junit.MockitoJUnitRunner; |
36 | 44 |
|
37 | 45 | import java.util.Arrays; |
| 46 | +import java.util.Collections; |
38 | 47 |
|
39 | 48 | import static org.junit.Assert.assertFalse; |
40 | 49 | import static org.junit.Assert.assertNotNull; |
41 | 50 | import static org.junit.Assert.assertTrue; |
| 51 | +import static org.mockito.Mockito.doReturn; |
42 | 52 | import static org.mockito.Mockito.mock; |
43 | 53 | import static org.mockito.Mockito.verify; |
44 | 54 | import static org.mockito.Mockito.when; |
@@ -66,6 +76,12 @@ public class KMSManagerImplHSMTest { |
66 | 76 | private DomainDao domainDao; |
67 | 77 | @Mock |
68 | 78 | private AccountDao accountDao; |
| 79 | + @Mock |
| 80 | + private KMSKeyDao kmsKeyDao; |
| 81 | + @Mock |
| 82 | + private KMSKekVersionDao kmsKekVersionDao; |
| 83 | + @Mock |
| 84 | + private KMSWrappedKeyDao kmsWrappedKeyDao; |
69 | 85 |
|
70 | 86 | /** |
71 | 87 | * Test: isSensitiveKey correctly identifies "pin" as sensitive |
@@ -157,4 +173,70 @@ public void testCreateHSMProfileResponse_PopulatesDetails() { |
157 | 173 | verify(hsmProfileDetailsDao).listByProfileId(profileId); |
158 | 174 | } |
159 | 175 | } |
| 176 | + |
| 177 | + /** |
| 178 | + * Test: the seeded default (system-owned) database profile cannot be deleted. |
| 179 | + */ |
| 180 | + @Test(expected = InvalidParameterValueException.class) |
| 181 | + public void testDeleteHSMProfile_RejectsSystemOwnedDatabaseProfile() { |
| 182 | + Long profileId = 10L; |
| 183 | + HSMProfileVO profile = mock(HSMProfileVO.class); |
| 184 | + when(profile.getProtocol()).thenReturn("database"); |
| 185 | + when(profile.getAccountId()).thenReturn(Account.ACCOUNT_ID_SYSTEM); |
| 186 | + when(profile.getIsPublic()).thenReturn(true); |
| 187 | + when(hsmProfileDao.findById(profileId)).thenReturn(profile); |
| 188 | + |
| 189 | + Account caller = mock(Account.class); |
| 190 | + when(caller.getId()).thenReturn(2L); |
| 191 | + when(accountManager.isRootAdmin(2L)).thenReturn(true); |
| 192 | + |
| 193 | + DeleteHSMProfileCmd cmd = mock(DeleteHSMProfileCmd.class); |
| 194 | + when(cmd.getId()).thenReturn(profileId); |
| 195 | + |
| 196 | + try (MockedStatic<CallContext> mockedCallContext = Mockito.mockStatic(CallContext.class)) { |
| 197 | + CallContext callContext = mock(CallContext.class); |
| 198 | + mockedCallContext.when(CallContext::current).thenReturn(callContext); |
| 199 | + when(callContext.getCallingAccount()).thenReturn(caller); |
| 200 | + |
| 201 | + kmsManager.deleteHSMProfile(cmd); |
| 202 | + } |
| 203 | + } |
| 204 | + |
| 205 | + /** |
| 206 | + * Test: an admin-created (non-system) database profile with no keys can be deleted. |
| 207 | + */ |
| 208 | + @Test |
| 209 | + public void testDeleteHSMProfile_AllowsAdminOwnedDatabaseProfile() { |
| 210 | + Long profileId = 10L; |
| 211 | + HSMProfileVO profile = mock(HSMProfileVO.class); |
| 212 | + when(profile.getId()).thenReturn(profileId); |
| 213 | + when(profile.getProtocol()).thenReturn("database"); |
| 214 | + when(profile.getAccountId()).thenReturn(200L); |
| 215 | + when(profile.getIsPublic()).thenReturn(false); |
| 216 | + when(hsmProfileDao.findById(profileId)).thenReturn(profile); |
| 217 | + |
| 218 | + when(kmsKeyDao.countByHsmProfileId(profileId)).thenReturn(0L); |
| 219 | + when(kmsKekVersionDao.listByHsmProfileId(profileId)).thenReturn(Collections.emptyList()); |
| 220 | + |
| 221 | + KMSProvider kmsProvider = mock(KMSProvider.class); |
| 222 | + doReturn(kmsProvider).when(kmsManager).getKMSProvider("database"); |
| 223 | + when(hsmProfileDao.remove(profileId)).thenReturn(true); |
| 224 | + |
| 225 | + Account caller = mock(Account.class); |
| 226 | + |
| 227 | + DeleteHSMProfileCmd cmd = mock(DeleteHSMProfileCmd.class); |
| 228 | + when(cmd.getId()).thenReturn(profileId); |
| 229 | + |
| 230 | + try (MockedStatic<CallContext> mockedCallContext = Mockito.mockStatic(CallContext.class)) { |
| 231 | + CallContext callContext = mock(CallContext.class); |
| 232 | + mockedCallContext.when(CallContext::current).thenReturn(callContext); |
| 233 | + when(callContext.getCallingAccount()).thenReturn(caller); |
| 234 | + |
| 235 | + boolean result = kmsManager.deleteHSMProfile(cmd); |
| 236 | + |
| 237 | + assertTrue("Admin-owned database profile should be deletable", result); |
| 238 | + verify(kmsProvider).invalidateProfileCache(profileId); |
| 239 | + verify(hsmProfileDao).remove(profileId); |
| 240 | + } |
| 241 | + } |
160 | 242 | } |
0 commit comments