From a44fc62d02500cacaff36558e191776827e600a8 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Wed, 14 Sep 2016 19:29:16 +0200 Subject: [PATCH] =?UTF-8?q?should=20be=20the=20only=20credentials=20per=20?= =?UTF-8?q?service=20name=20=E2=80=94=20fixed=20and=20tested=20for=20macOS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/KeePassCredentialStore.kt | 2 +- .../credential-store/src/credentialStore.kt | 8 ++++-- .../src/macOsKeychainLibrary.kt | 28 ++++++++++++++++--- .../test/CredentialStoreTest.kt | 21 +++++++++++--- 4 files changed, 48 insertions(+), 11 deletions(-) diff --git a/platform/credential-store/src/KeePassCredentialStore.kt b/platform/credential-store/src/KeePassCredentialStore.kt index 047e104ff078..a13fc50b8254 100644 --- a/platform/credential-store/src/KeePassCredentialStore.kt +++ b/platform/credential-store/src/KeePassCredentialStore.kt @@ -135,8 +135,8 @@ internal class KeePassCredentialStore(keyToValue: Map, userName: String) = CredentialAttributes("IntelliJ Platform", toOldKey(MessageDigest.getInstance("SHA-256").digest("${requestor.name}/$userName".toByteArray()))) +fun toOldKey(requestor: Class<*>, userName: String): CredentialAttributes { + return CredentialAttributes(SERVICE_NAME_PREFIX, toOldKey(MessageDigest.getInstance("SHA-256").digest("${requestor.name}/$userName".toByteArray()))) +} fun joinData(user: String?, password: OneTimeString?): ByteArray? { if (user == null && password == null) { diff --git a/platform/credential-store/src/macOsKeychainLibrary.kt b/platform/credential-store/src/macOsKeychainLibrary.kt index fcaf49cdfda9..87b8115912a4 100644 --- a/platform/credential-store/src/macOsKeychainLibrary.kt +++ b/platform/credential-store/src/macOsKeychainLibrary.kt @@ -59,15 +59,29 @@ internal class KeyChainCredentialStore() : CredentialStore { val password = credentials!!.password?.toByteArray(false) val userName = (attributes.userName ?: credentials.userName)?.toByteArray() + val searchUserName = if (attributes.serviceName == SERVICE_NAME_PREFIX) userName else null val itemRef = PointerByReference() val library = LIBRARY - checkForError("find (for save)", library.SecKeychainFindGenericPassword(null, serviceName.size, serviceName, userName?.size ?: 0, userName, null, null, itemRef)) + checkForError("find (for save)", library.SecKeychainFindGenericPassword(null, serviceName.size, serviceName, searchUserName?.size ?: 0, searchUserName, null, null, itemRef)) val pointer = itemRef.value if (pointer == null) { checkForError("save (new)", library.SecKeychainAddGenericPassword(null, serviceName.size, serviceName, userName?.size ?: 0, userName, password?.size ?: 0, password)) } else { - checkForError("save (update)", library.SecKeychainItemModifyContent(pointer, null, password?.size ?: 0, password)) + val attribute = SecKeychainAttribute() + attribute.tag = kSecAccountItemAttr + attribute.length = userName?.size ?: 0 + if (userName != null) { + val userNamePointer = Memory(userName.size.toLong()) + userNamePointer.write(0, userName, 0, userName.size) + attribute.data = userNamePointer + } + + val attributeList = SecKeychainAttributeList() + attributeList.count = 1 + attribute.write() + attributeList.attr = attribute.pointer + checkForError("save (update)", library.SecKeychainItemModifyContent(pointer, attributeList, password?.size ?: 0, password)) library.CFRelease(pointer) } @@ -107,7 +121,7 @@ fun findGenericPassword(serviceName: ByteArray, accountName: String?): Credentia private interface MacOsKeychainLibrary : Library { fun SecKeychainAddGenericPassword(keychain: Pointer?, serviceNameLength: Int, serviceName: ByteArray, accountNameLength: Int, accountName: ByteArray?, passwordLength: Int, passwordData: ByteArray?, itemRef: Pointer? = null): Int - fun SecKeychainItemModifyContent(itemRef: Pointer, /*SecKeychainAttributeList**/ attrList: Pointer?, length: Int, data: ByteArray?): Int + fun SecKeychainItemModifyContent(itemRef: Pointer, /*SecKeychainAttributeList**/ attrList: Any?, length: Int, data: ByteArray?): Int fun SecKeychainFindGenericPassword(keychainOrArray: Pointer?, serviceNameLength: Int, @@ -201,10 +215,13 @@ internal class SecKeychainAttributeList : Structure { constructor(p: Pointer) : super(p) { } + constructor() : super() { + } + override fun getFieldOrder() = listOf("count", "attr") } -internal class SecKeychainAttribute : Structure { +internal class SecKeychainAttribute : Structure, Structure.ByReference { @JvmField var tag = 0 @JvmField @@ -215,6 +232,9 @@ internal class SecKeychainAttribute : Structure { internal constructor(p: Pointer) : super(p) { } + internal constructor() : super() { + } + override fun getFieldOrder() = listOf("tag", "length", "data") } diff --git a/platform/credential-store/test/CredentialStoreTest.kt b/platform/credential-store/test/CredentialStoreTest.kt index 1111e253bb99..9601350659e5 100644 --- a/platform/credential-store/test/CredentialStoreTest.kt +++ b/platform/credential-store/test/CredentialStoreTest.kt @@ -28,7 +28,7 @@ internal class CredentialStoreTest { } @Test - fun keepass() { + fun KeePass() { doTest(KeePassCredentialStore()) } @@ -41,6 +41,15 @@ internal class CredentialStoreTest { testEmptyAccountName(KeyChainCredentialStore()) } + @Test + fun `mac - changedAccountName`() { + if (!SystemInfo.isMacIntel64 || UsefulTestCase.IS_UNDER_TEAMCITY) { + return + } + + testChangedAccountName(KeyChainCredentialStore()) + } + @Test fun `linux - testEmptyAccountName`() { if (!SystemInfo.isLinux || UsefulTestCase.IS_UNDER_TEAMCITY) { @@ -51,12 +60,12 @@ internal class CredentialStoreTest { } @Test - fun `keepass - testEmptyAccountName`() { + fun `KeePass - testEmptyAccountName`() { testEmptyAccountName(KeePassCredentialStore()) } @Test - fun `keepass - testChangedAccountName`() { + fun `KeePass - changedAccountName`() { testChangedAccountName(KeePassCredentialStore()) } @@ -103,12 +112,16 @@ internal class CredentialStoreTest { val serviceNameOnlyAttributes = CredentialAttributes("Test IJ — ${randomString()}") try { val credentials = Credentials(randomString(), "pass") - val newUserName = randomString() + var newUserName = randomString() val newPassword = randomString() store.set(serviceNameOnlyAttributes, credentials) assertThat(store.get(serviceNameOnlyAttributes)).isEqualTo(credentials) store.set(CredentialAttributes(serviceNameOnlyAttributes.serviceName, newUserName), Credentials(newUserName, newPassword)) assertThat(store.get(serviceNameOnlyAttributes)).isEqualTo(Credentials(newUserName, newPassword)) + + newUserName = randomString() + store.set(CredentialAttributes(serviceNameOnlyAttributes.serviceName, newUserName), Credentials(newUserName, newPassword)) + assertThat(store.get(serviceNameOnlyAttributes)!!.userName).isEqualTo(newUserName) } finally { store.set(serviceNameOnlyAttributes, null)