diff --git a/backends/credhub/src/main/kotlin/org/cloudfoundry/credhub/credentials/RemoteCredentialsHandler.kt b/backends/credhub/src/main/kotlin/org/cloudfoundry/credhub/credentials/RemoteCredentialsHandler.kt index 934ed3670..f4408d6b7 100644 --- a/backends/credhub/src/main/kotlin/org/cloudfoundry/credhub/credentials/RemoteCredentialsHandler.kt +++ b/backends/credhub/src/main/kotlin/org/cloudfoundry/credhub/credentials/RemoteCredentialsHandler.kt @@ -515,8 +515,8 @@ class RemoteCredentialsHandler( if (jsonNode.hasNonNull("exclude_lower")) { generationParameters.excludeLower = jsonNode["exclude_lower"].booleanValue() } - if (jsonNode.hasNonNull("exlude_upper")) { - generationParameters.excludeUpper = jsonNode["exlude_upper"].booleanValue() + if (jsonNode.hasNonNull("exclude_upper")) { + generationParameters.excludeUpper = jsonNode["exclude_upper"].booleanValue() } if (jsonNode.hasNonNull("exclude_number")) { generationParameters.excludeNumber = jsonNode["exclude_number"].booleanValue() @@ -543,8 +543,8 @@ class RemoteCredentialsHandler( if (jsonNode.hasNonNull("exclude_lower")) { generationParameters.excludeLower = jsonNode["exclude_lower"].booleanValue() } - if (jsonNode.hasNonNull("exlude_upper")) { - generationParameters.excludeUpper = jsonNode["exlude_upper"].booleanValue() + if (jsonNode.hasNonNull("exclude_upper")) { + generationParameters.excludeUpper = jsonNode["exclude_upper"].booleanValue() } if (jsonNode.hasNonNull("exclude_number")) { generationParameters.excludeNumber = jsonNode["exclude_number"].booleanValue() diff --git a/backends/credhub/src/test/kotlin/org/cloudfoundry/credhub/handlers/RemoteCredentialsHandlerTest.kt b/backends/credhub/src/test/kotlin/org/cloudfoundry/credhub/handlers/RemoteCredentialsHandlerTest.kt index a92cb7475..8f8a9e705 100644 --- a/backends/credhub/src/test/kotlin/org/cloudfoundry/credhub/handlers/RemoteCredentialsHandlerTest.kt +++ b/backends/credhub/src/test/kotlin/org/cloudfoundry/credhub/handlers/RemoteCredentialsHandlerTest.kt @@ -1355,6 +1355,52 @@ class RemoteCredentialsHandlerTest { assertThat(actualValue).isEqualTo(shouldBeReturned.username) } + @Test + fun generateUser_whenParsingGenerationParameters_preservesAllFields() { + val type = "user" + val uuid = UUID.randomUUID().toString() + val userCredential = UserCredentialValue("test-user", "test-password", "salt") + + // Create generation parameters with ALL fields set + val originalGenerationParameters = StringGenerationParameters() + originalGenerationParameters.length = 15 + originalGenerationParameters.username = "test-username" + originalGenerationParameters.excludeLower = false + originalGenerationParameters.excludeUpper = true + originalGenerationParameters.excludeNumber = true + originalGenerationParameters.includeSpecial = false + + // Serialize to ByteString (as remote backend would) + val generationParamsByteString = subject.createByteStringFromGenerationParameters(type, originalGenerationParameters) + + // Create a GetResponse with these generation parameters (simulating remote backend response) + val getResponse = + GetResponse + .newBuilder() + .setName(CREDENTIAL_NAME) + .setType(type) + .setData(subject.createByteStringFromData(type, userCredential)) + .setId(uuid) + .setVersionCreatedAt(versionCreatedAt) + .setGenerationParameters(generationParamsByteString) + .build() + + `when`(client.getByNameRequest(CREDENTIAL_NAME, USER)).thenReturn(getResponse) + + // Create a new request with matching parameters + val userGenerateRequest = UserGenerateRequest() + userGenerateRequest.setGenerationParameters(originalGenerationParameters) + userGenerateRequest.name = CREDENTIAL_NAME + userGenerateRequest.type = type + + // This should NOT regenerate because parameters match + val generateResponse = subject.generateCredential(userGenerateRequest) + + // Verify the credential was not regenerated (existing one returned) + assertThat(generateResponse.getUuid()).isEqualTo(uuid) + assertThat((generateResponse.value as UserCredentialValue).username).isEqualTo("test-user") + } + @Test fun generatePassword_whenExistingPasswordGenerationParametersDontMatch_generateNewCredential() { val type = "password" @@ -1530,6 +1576,52 @@ class RemoteCredentialsHandlerTest { assertThat(actualValue).isEqualTo(originalPassword.stringCredential.toString()) } + @Test + fun generatePassword_whenParsingGenerationParameters_preservesAllFields() { + val type = "password" + val uuid = UUID.randomUUID().toString() + val password = StringCredentialValue("test-password") + + // Create generation parameters with ALL fields set + val originalGenerationParameters = StringGenerationParameters() + originalGenerationParameters.length = 20 + originalGenerationParameters.username = "test-user" + originalGenerationParameters.excludeLower = false + originalGenerationParameters.excludeUpper = true + originalGenerationParameters.excludeNumber = true + originalGenerationParameters.includeSpecial = true + + // Serialize to ByteString (as remote backend would) + val generationParamsByteString = subject.createByteStringFromGenerationParameters(type, originalGenerationParameters) + + // Create a GetResponse with these generation parameters (simulating remote backend response) + val getResponse = + GetResponse + .newBuilder() + .setName(CREDENTIAL_NAME) + .setType(type) + .setData(subject.createByteStringFromData(type, password)) + .setId(uuid) + .setVersionCreatedAt(versionCreatedAt) + .setGenerationParameters(generationParamsByteString) + .build() + + `when`(client.getByNameRequest(CREDENTIAL_NAME, USER)).thenReturn(getResponse) + + // Create a new request with matching parameters + val passwordGenerateRequest = PasswordGenerateRequest() + passwordGenerateRequest.generationParameters = originalGenerationParameters + passwordGenerateRequest.name = CREDENTIAL_NAME + passwordGenerateRequest.type = type + + // This should NOT regenerate because parameters match + val generateResponse = subject.generateCredential(passwordGenerateRequest) + + // Verify the credential was not regenerated (existing one returned) + assertThat(generateResponse.getUuid()).isEqualTo(uuid) + assertThat((generateResponse.value as StringCredentialValue).stringCredential).isEqualTo("test-password") + } + @Test fun getCredentialByName_whenCredentialDoesNotExist_throwsCorrectError() { val exception = StatusRuntimeException(Status.NOT_FOUND)