Skip to content

Commit 42552ea

Browse files
authored
Merge pull request #688 from openziti/fix-load-bytes
fix loading KeyStore bytes
2 parents 3637d19 + 0bc0a2d commit 42552ea

File tree

4 files changed

+100
-26
lines changed

4 files changed

+100
-26
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright (c) 2018-2025 NetFoundry Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.openziti.impl
18+
19+
import kotlinx.serialization.json.Json
20+
import org.junit.jupiter.api.AfterEach
21+
import org.junit.jupiter.api.Assertions.assertEquals
22+
import org.junit.jupiter.api.BeforeEach
23+
import org.junit.jupiter.api.Test
24+
import org.openziti.IdentityConfig
25+
import org.openziti.Ziti
26+
import org.openziti.identity.keystoreFromConfig
27+
import org.openziti.integ.BaseTest
28+
import java.io.ByteArrayOutputStream
29+
30+
class LoadTests: BaseTest() {
31+
lateinit var cfg: IdentityConfig
32+
@BeforeEach
33+
fun before() {
34+
cfg = createIdentity()
35+
}
36+
37+
@AfterEach
38+
fun after() {
39+
Ziti.getContexts().forEach {
40+
it.destroy()
41+
}
42+
}
43+
44+
@Test
45+
fun testLoadConfigByteArray() {
46+
val cfgBytes = Json.encodeToString(cfg).toByteArray(Charsets.UTF_8)
47+
48+
Ziti.init(cfgBytes, false)
49+
50+
val contexts = Ziti.getContexts()
51+
assertEquals(1, contexts.size)
52+
}
53+
54+
@Test
55+
fun testLoadKeyStoreByteArray() {
56+
val ks = keystoreFromConfig(cfg)
57+
val output = ByteArrayOutputStream()
58+
ks.store(output, charArrayOf())
59+
60+
val storeBtes = output.toByteArray()
61+
Ziti.init(storeBtes, false)
62+
63+
val contexts = Ziti.getContexts()
64+
assertEquals(1, contexts.size)
65+
}
66+
}

ziti/src/main/kotlin/org/openziti/Ziti.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@
1616

1717
package org.openziti
1818

19+
import kotlinx.coroutines.CoroutineScope
20+
import kotlinx.coroutines.Dispatchers
21+
import kotlinx.coroutines.channels.Channel
1922
import kotlinx.coroutines.flow.Flow
23+
import kotlinx.coroutines.launch
24+
import kotlinx.coroutines.runBlocking
2025
import org.openziti.api.Service
2126
import org.openziti.identity.Enroller
2227
import org.openziti.impl.ZitiImpl
@@ -29,6 +34,8 @@ import java.io.InputStream
2934
import java.net.InetSocketAddress
3035
import java.net.SocketAddress
3136
import java.security.KeyStore
37+
import java.util.function.Consumer
38+
import java.util.stream.Stream
3239
import javax.net.SocketFactory
3340
import javax.net.ssl.SSLContext
3441
import javax.net.ssl.SSLSocketFactory
@@ -122,16 +129,18 @@ object Ziti {
122129
fun connect(addr: SocketAddress): ZitiConnection = ZitiImpl.connect(addr)
123130

124131
@JvmStatic
125-
fun getContexts(): Collection<ZitiContext> = ZitiImpl.contexts
132+
fun getContexts(): Collection<ZitiContext> = ZitiImpl.contexts.value
126133

127134
@JvmStatic
128135
fun setApplicationInfo(id: String, version: String) = ZitiImpl.setApplicationInfo(id, version)
129136

130137
@JvmStatic
131138
fun getServiceFor(host: String, port: Int): Pair<ZitiContext, Service>? = ZitiImpl.getServiceFor(host, port)
132139

140+
@JvmStatic
133141
fun getServiceFor(addr: InetSocketAddress): Pair<ZitiContext, Service>? = ZitiImpl.getServiceFor(addr)
134142

143+
@JvmStatic
135144
fun findDialInfo(addr: InetSocketAddress): Pair<ZitiContext, SocketAddress>? = ZitiImpl.findDialInfo(addr)
136145

137146
fun serviceUpdates(): Flow<Pair<ZitiContext, ZitiContext.ServiceEvent>> = ZitiImpl.serviceUpdates()

ziti/src/main/kotlin/org/openziti/impl/ZitiContextImpl.kt

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -191,12 +191,6 @@ internal class ZitiContextImpl(internal val id: Identity, enabled: Boolean) : Zi
191191
return conn
192192
}
193193

194-
internal fun dialById(serviceId: String): ZitiConnection =
195-
servicesById[serviceId]?.let {
196-
dial(it.name)
197-
} ?: throw ZitiException(ZitiException.Errors.ServiceNotAvailable)
198-
199-
200194
internal fun dial(host: String, port: Int): ZitiConnection {
201195
val service = getServiceForAddress(host, port) ?: throw ZitiException(Errors.ServiceNotAvailable)
202196
return dial(service.name)
@@ -325,6 +319,9 @@ internal class ZitiContextImpl(internal val id: Identity, enabled: Boolean) : Zi
325319
}
326320

327321
override fun destroy() {
322+
Ziti.removeContext(this)
323+
if (supervisor.isCompleted) return
324+
328325
d{"stopping networking"}
329326
stop()
330327
d{"stopping controller"}

ziti/src/main/kotlin/org/openziti/impl/ZitiImpl.kt

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import kotlinx.coroutines.launch
2121
import kotlinx.coroutines.runBlocking
2222
import org.openziti.*
2323
import org.openziti.api.Service
24-
import org.openziti.identity.Enroller
2524
import org.openziti.identity.KeyStoreIdentity
2625
import org.openziti.identity.findIdentityAlias
2726
import org.openziti.identity.loadKeystore
@@ -38,7 +37,7 @@ import java.net.URI
3837
import java.security.KeyStore
3938

4039
internal object ZitiImpl : Logged by ZitiLog() {
41-
internal val contexts = mutableListOf<ZitiContextImpl>()
40+
internal val contexts = MutableStateFlow<Collection<ZitiContextImpl>>(emptyList())
4241
internal var appId = ""
4342
internal var appVersion = ""
4443

@@ -48,7 +47,7 @@ internal object ZitiImpl : Logged by ZitiLog() {
4847
try {
4948
Class.forName("android.util.Log")
5049
true
51-
} catch (cnf: ClassNotFoundException) {
50+
} catch (_: ClassNotFoundException) {
5251
false
5352
}
5453
}
@@ -59,7 +58,7 @@ internal object ZitiImpl : Logged by ZitiLog() {
5958

6059
fun loadContext(cfg: IdentityConfig, enabled: Boolean) =
6160
ZitiContextImpl(cfg, enabled).also { ztx ->
62-
contexts.add(ztx)
61+
contexts.value += ztx
6362
ztx.launch {
6463
ztxEvents.emit(Ziti.IdentityEvent(Ziti.IdentityEventType.Loaded, ztx))
6564
ztx.serviceUpdates().collect {
@@ -73,7 +72,7 @@ internal object ZitiImpl : Logged by ZitiLog() {
7372
val idName = alias ?: findIdentityAlias(ks)
7473
val id = KeyStoreIdentity(ks, idName)
7574
return ZitiContextImpl(id, true).also { ctx ->
76-
contexts.add(ctx)
75+
contexts.value += ctx
7776
ctx.launch {
7877
ztxEvents.emit(Ziti.IdentityEvent(Ziti.IdentityEventType.Loaded, ctx))
7978
ctx.serviceUpdates().collect {
@@ -95,10 +94,11 @@ internal object ZitiImpl : Logged by ZitiLog() {
9594
return loadContext(ks, alias)
9695
}
9796

98-
internal fun loadContext(id: ByteArray): ZitiContextImpl {
99-
val ks = loadKeystore(id)
100-
return loadContext(ks, null)
101-
}
97+
internal fun loadContext(id: ByteArray): ZitiContextImpl =
98+
id.inputStream().use {
99+
val ks = loadKeystore(it, charArrayOf())
100+
loadContext(ks, null)
101+
}
102102

103103
fun init(c: ByteArray, seamless: Boolean) {
104104
initInternalNetworking(seamless)
@@ -115,14 +115,16 @@ internal object ZitiImpl : Logged by ZitiLog() {
115115
}
116116

117117
fun removeContext(ctx: ZitiContext) {
118-
contexts.remove(ctx)
119-
if(ctx is ZitiContextImpl) {
118+
119+
if(ctx is ZitiContextImpl && contexts.value.contains(ctx)) {
120+
val ctxs = contexts.value - ctx
121+
contexts.value = ctxs
120122
runBlocking { ztxEvents.emit(Ziti.IdentityEvent(Ziti.IdentityEventType.Removed, ctx)) }
121123
ctx.destroy()
122124
}
123125
}
124126

125-
fun init(ks: KeyStore, seamless: Boolean): List<ZitiContext> {
127+
fun init(ks: KeyStore, seamless: Boolean): Collection<ZitiContext> {
126128
initInternalNetworking(seamless)
127129

128130
for (a in ks.aliases()) {
@@ -131,7 +133,7 @@ internal object ZitiImpl : Logged by ZitiLog() {
131133
}
132134
}
133135

134-
return contexts
136+
return contexts.value
135137
}
136138

137139
private fun isZitiIdentity(ks: KeyStore, alias: String): Boolean =
@@ -155,9 +157,9 @@ internal object ZitiImpl : Logged by ZitiLog() {
155157
return ZitiDNSManager.lookup(addr.address)?.let { getServiceFor(it, addr.port) }
156158
}
157159

158-
fun getServiceFor(host: String, port: Int): Pair<ZitiContext, Service>? = contexts.map { c ->
159-
c.getServiceForAddress(host, port)?.let { Pair(c, it) }
160-
}.filterNotNull().firstOrNull()
160+
fun getServiceFor(host: String, port: Int): Pair<ZitiContext, Service>? = contexts.value.firstNotNullOfOrNull { c ->
161+
c.getServiceForAddress(host, port)?.let { Pair(c, it) }
162+
}
161163

162164
fun connect(addr: SocketAddress): ZitiConnection {
163165
when (addr) {
@@ -166,7 +168,7 @@ internal object ZitiImpl : Logged by ZitiLog() {
166168
return ztx.dial(svc.name)
167169
}
168170
is ZitiAddress.Dial -> {
169-
for (c in contexts) {
171+
for (c in contexts.value) {
170172
c.getService(addr.service)?.let {
171173
return c.dial(addr)
172174
}
@@ -189,14 +191,14 @@ internal object ZitiImpl : Logged by ZitiLog() {
189191

190192
private val ztxEvents = MutableSharedFlow<Ziti.IdentityEvent>()
191193
internal fun getEvents(): Flow<Ziti.IdentityEvent> = flow {
192-
contexts.forEach {
194+
contexts.value.forEach {
193195
emit(Ziti.IdentityEvent(Ziti.IdentityEventType.Loaded, it))
194196
}
195197
emitAll(ztxEvents)
196198
}
197199

198200
fun findDialInfo(addr: InetSocketAddress): Pair<ZitiContext, SocketAddress>? {
199-
for (c in contexts) {
201+
for (c in contexts.value) {
200202
val dial = c.getDialAddress(addr)
201203
if (dial != null) {
202204
return c to dial

0 commit comments

Comments
 (0)