mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
should be the only credentials per service name — fixed and tested for macOS
This commit is contained in:
@@ -135,8 +135,8 @@ internal class KeePassCredentialStore(keyToValue: Map<CredentialAttributes, Cred
|
||||
else {
|
||||
val group = db.rootGroup.getOrCreateGroup(GROUP_NAME)
|
||||
// should be the only credentials per service name — find without user name
|
||||
var entry = group.getEntry(attributes.serviceName, null)
|
||||
val userName = attributes.userName ?: credentials.userName
|
||||
var entry = group.getEntry(attributes.serviceName, if (attributes.serviceName == SERVICE_NAME_PREFIX) userName else null)
|
||||
if (entry == null) {
|
||||
entry = group.getOrCreateEntry(attributes.serviceName, userName)
|
||||
}
|
||||
|
||||
@@ -27,11 +27,15 @@ import javax.crypto.spec.SecretKeySpec
|
||||
|
||||
internal val LOG = Logger.getInstance(CredentialStore::class.java)
|
||||
|
||||
internal val SERVICE_NAME_PREFIX = "IntelliJ Platform"
|
||||
|
||||
private fun toOldKey(hash: ByteArray) = "old-hashed-key|" + Base64.getEncoder().encodeToString(hash)
|
||||
|
||||
internal fun toOldKeyAsIdentity(hash: ByteArray) = CredentialAttributes("IntelliJ Platform", toOldKey(hash))
|
||||
internal fun toOldKeyAsIdentity(hash: ByteArray) = CredentialAttributes(SERVICE_NAME_PREFIX, toOldKey(hash))
|
||||
|
||||
fun toOldKey(requestor: Class<*>, 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) {
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user