Skip to content

Commit f850d1a

Browse files
author
Robert Winkler
committed
Added Credentials support for client mode.
1 parent 92e21c7 commit f850d1a

File tree

49 files changed

+1011
-406
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1011
-406
lines changed

kotlin-wot-binding-http/src/main/kotlin/http/HttpProtocolClient.kt

Lines changed: 12 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
package ai.ancf.lmos.wot.binding.http
22

33
import ai.ancf.lmos.wot.content.Content
4-
import ai.ancf.lmos.wot.security.BasicSecurityScheme
5-
import ai.ancf.lmos.wot.security.BearerSecurityScheme
6-
import ai.ancf.lmos.wot.security.NoSecurityScheme
7-
import ai.ancf.lmos.wot.security.SecurityScheme
8-
import ai.ancf.lmos.wot.thing.form.Form
4+
import ai.ancf.lmos.wot.credentials.CredentialsProvider
5+
import ai.ancf.lmos.wot.thing.schema.WoTForm
96
import ai.anfc.lmos.wot.binding.ProtocolClient
107
import ai.anfc.lmos.wot.binding.ProtocolClientException
11-
import http.HttpClientConfig
128
import io.ktor.client.*
139
import io.ktor.client.engine.*
1410
import io.ktor.client.engine.cio.*
@@ -21,31 +17,29 @@ import kotlinx.coroutines.flow.flow
2117
import kotlinx.coroutines.flow.flowOn
2218
import org.slf4j.LoggerFactory
2319
import java.time.Duration
24-
import java.util.*
2520

2621
/**
2722
* Allows consuming Things via HTTP.
2823
*/
2924
class HttpProtocolClient(
30-
private val httpClientConfig: HttpClientConfig? = null,
3125
private val client: HttpClient = createHttpClient()
3226
) : ProtocolClient {
3327

34-
private var authorization: String? = null
28+
private var credentialsProvider: CredentialsProvider? = null
3529

36-
override suspend fun readResource(form: Form):Content {
30+
override suspend fun readResource(form: WoTForm):Content {
3731
return resolveRequestToContent(form, HttpMethod.Get)
3832
}
3933

40-
override suspend fun writeResource(form: Form, content: Content) {
34+
override suspend fun writeResource(form: WoTForm, content: Content) {
4135
resolveRequestToContent(form, HttpMethod.Put, content)
4236
}
4337

44-
override suspend fun invokeResource(form: Form, content: Content?): Content {
38+
override suspend fun invokeResource(form: WoTForm, content: Content?): Content {
4539
return resolveRequestToContent(form, HttpMethod.Post, content)
4640
}
4741

48-
override suspend fun subscribeResource(form: Form) = flow {
42+
override suspend fun subscribeResource(form: WoTForm) = flow {
4943
// Long-polling logic using Ktor client
5044
while (true) {
5145
try {
@@ -68,36 +62,11 @@ class HttpProtocolClient(
6862
TODO("Not yet implemented")
6963
}
7064

71-
override fun setSecurity(metadata: List<SecurityScheme>, credentials: Map<String, String>): Boolean {
72-
if (metadata.isEmpty()) {
73-
log.warn("HttpClient without security")
74-
return false
75-
}
76-
77-
return when (val security = metadata.firstOrNull()) {
78-
is BasicSecurityScheme -> {
79-
val credentialsMap = credentials
80-
val username = credentialsMap["username"]
81-
val password = credentialsMap["password"]
82-
val basicAuth = Base64.getEncoder().encodeToString("$username:$password".toByteArray())
83-
authorization = "Basic $basicAuth"
84-
true
85-
}
86-
is BearerSecurityScheme -> {
87-
val credentialsMap = credentials
88-
val token = credentialsMap["token"]
89-
authorization = "Bearer $token"
90-
true
91-
}
92-
is NoSecurityScheme -> true
93-
else -> {
94-
log.error("HttpClient cannot set security scheme '{}'", security)
95-
false
96-
}
97-
}
65+
override fun setCredentialsProvider(credentialsProvider: CredentialsProvider){
66+
this.credentialsProvider = credentialsProvider
9867
}
9968

100-
private suspend fun resolveRequestToContent(form: Form, method: HttpMethod, content: Content? = null): Content {
69+
private suspend fun resolveRequestToContent(form: WoTForm, method: HttpMethod, content: Content? = null): Content {
10170
return try {
10271
val response: HttpResponse = client.request(form.href) {
10372
headers {
@@ -106,11 +75,11 @@ class HttpProtocolClient(
10675
this.method = method
10776
content?.let {
10877
headers {
109-
append(HttpHeaders.ContentType, it.type )
78+
append(HttpHeaders.ContentType, form.contentType )
11079
}
11180
setBody(it.body)
11281
}
113-
authorization?.let { headers.append(HttpHeaders.Authorization, it) }
82+
credentialsProvider?.getCredentials(form).let { headers.append(HttpHeaders.Authorization, it.toString()) }
11483
}
11584
checkResponse(response)
11685
} catch (e: Exception) {
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,17 @@
11
package ai.ancf.lmos.wot.binding.http
22

3+
import ai.anfc.lmos.wot.binding.ProtocolClient
34
import ai.anfc.lmos.wot.binding.ProtocolClientFactory
4-
import http.HttpClientConfig
55

66
/**
77
* Creates new [HttpProtocolClient] instances.
88
*/
9-
open class HttpProtocolClientFactory(private val httpClientConfig: HttpClientConfig? = null) : ProtocolClientFactory {
9+
open class HttpProtocolClientFactory() : ProtocolClientFactory {
1010
override fun toString(): String {
1111
return "HttpClient"
1212
}
1313
override val scheme: String
1414
get() = "http"
15-
override val client: HttpProtocolClient
16-
get() = HttpProtocolClient(httpClientConfig)
1715

1816
override suspend fun init() {
1917
// TODO
@@ -22,4 +20,6 @@ open class HttpProtocolClientFactory(private val httpClientConfig: HttpClientCon
2220
override suspend fun destroy() {
2321
// TODO
2422
}
23+
24+
override fun createClient(): ProtocolClient = HttpProtocolClient()
2525
}

kotlin-wot-binding-http/src/main/kotlin/http/routes/AbstractInteractionRoute.kt

Lines changed: 0 additions & 47 deletions
This file was deleted.

kotlin-wot-binding-http/src/test/kotlin/http/HttpProtocolClientFactoryTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ class HttpProtocolClientFactoryTest {
1212

1313
@Test
1414
fun getClient() {
15-
assertIs<HttpProtocolClient>( HttpProtocolClientFactory().client)
15+
assertIs<HttpProtocolClient>( HttpProtocolClientFactory().createClient())
1616
}
1717
}

kotlin-wot-binding-http/src/test/kotlin/http/HttpProtocolClientTest.kt

Lines changed: 3 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class HttpProtocolClientTest {
4444
statusCode = 200
4545
}
4646

47-
every { form.href } returns "${wiremock.baseUrl()}/foo"
47+
val form = Form("${wiremock.baseUrl()}/foo")
4848

4949
val client = HttpProtocolClient()
5050
client.readResource(form)
@@ -64,7 +64,7 @@ class HttpProtocolClientTest {
6464
statusCode = 200
6565
}
6666

67-
every { form.href } returns "${wiremock.baseUrl()}/foo"
67+
val form = Form("${wiremock.baseUrl()}/foo")
6868
val jsonContent = """{"key": "value"}"""
6969
val content = Content("application/json", jsonContent.toByteArray())
7070

@@ -86,7 +86,7 @@ class HttpProtocolClientTest {
8686
statusCode = 200
8787
}
8888

89-
every { form.href } returns "${wiremock.baseUrl()}/foo"
89+
val form = Form("${wiremock.baseUrl()}/foo")
9090
val jsonContent = """{"key": "value"}"""
9191
val content = Content("application/json", jsonContent.toByteArray())
9292

@@ -114,48 +114,6 @@ class HttpProtocolClientTest {
114114

115115
}
116116

117-
@Test
118-
fun setSecurityHandlesBasicSecurityScheme() {
119-
val client = HttpProtocolClient()
120-
val credentials = mapOf("username" to "user", "password" to "pass")
121-
val securityScheme = BasicSecurityScheme()
122-
123-
val result = client.setSecurity(listOf(securityScheme), credentials)
124-
125-
assert(result)
126-
}
127-
128-
@Test
129-
fun setSecurityHandlesBearerSecurityScheme() {
130-
val client = HttpProtocolClient()
131-
val credentials = mapOf("token" to "token123")
132-
val securityScheme = BearerSecurityScheme()
133-
134-
val result = client.setSecurity(listOf(securityScheme), credentials)
135-
136-
assert(result)
137-
}
138-
139-
@Test
140-
fun setSecurityHandlesNoSecurityScheme() {
141-
val client = HttpProtocolClient()
142-
val securityScheme = NoSecurityScheme()
143-
144-
val result = client.setSecurity(listOf(securityScheme), emptyMap())
145-
146-
assert(result)
147-
}
148-
149-
@Test
150-
fun setSecurityThrowsExceptionForUnknownScheme() {
151-
val client = HttpProtocolClient()
152-
val securityScheme = mockk<SecurityScheme>()
153-
154-
val result = client.setSecurity(listOf(securityScheme), emptyMap())
155-
156-
assert(!result)
157-
}
158-
159117
@Test
160118
fun resolveRequestToContentThrowsExceptionForInvalidResponse() = runTest {
161119
wiremock.get {

kotlin-wot-binding-http/src/test/kotlin/http/HttpsProtocolClientFactoryTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ class HttpsProtocolClientFactoryTest {
1313

1414
@Test
1515
fun getClient() {
16-
assertIs<HttpProtocolClient>( HttpsProtocolClientFactory().client)
16+
assertIs<HttpProtocolClient>( HttpsProtocolClientFactory().createClient())
1717
}
1818
}

kotlin-wot-binding-mqtt/src/main/kotlin/mqtt/MqttProtocolClient.kt

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
package ai.ancf.lmos.wot.binding.mqtt
22

33
import ai.ancf.lmos.wot.content.Content
4-
import ai.ancf.lmos.wot.thing.form.Form
4+
import ai.ancf.lmos.wot.credentials.CredentialsProvider
5+
import ai.ancf.lmos.wot.thing.schema.WoTForm
56
import ai.anfc.lmos.wot.binding.ProtocolClient
67
import ai.anfc.lmos.wot.binding.ProtocolClientException
78
import com.hivemq.client.mqtt.datatypes.MqttQos
@@ -32,7 +33,7 @@ class MqttProtocolClient(
3233

3334
private val topicChannels = ConcurrentHashMap<String, Channel<Content>>()
3435

35-
override suspend fun invokeResource(form: Form, content: Content?): Content {
36+
override suspend fun invokeResource(form: WoTForm, content: Content?): Content {
3637
val topic = try {
3738
URI(form.href).path.substring(1)
3839
} catch (e: URISyntaxException) {
@@ -41,7 +42,7 @@ class MqttProtocolClient(
4142
return requestReply(form, content, topic)
4243
}
4344

44-
override suspend fun subscribeResource(form: Form): Flow<Content> {
45+
override suspend fun subscribeResource(form: WoTForm): Flow<Content> {
4546
val topic = try {
4647
URI(form.href).path.substring(1)
4748
}
@@ -51,7 +52,7 @@ class MqttProtocolClient(
5152
return subscribeToTopic(form, topic)
5253
}
5354

54-
override suspend fun unlinkResource(form: Form) {
55+
override suspend fun unlinkResource(form: WoTForm) {
5556
val topic = try {
5657
URI(form.href).path.substring(1)
5758
}
@@ -95,7 +96,7 @@ class MqttProtocolClient(
9596
}
9697

9798
// Function to observe a topic using HiveMQ Mqtt5AsyncClient
98-
private suspend fun subscribeToTopic(form: Form, topic: String): Flow<Content> {
99+
private suspend fun subscribeToTopic(form: WoTForm, topic: String): Flow<Content> {
99100
log.debug("MqttClient connected to broker at '{}:{}' subscribing to topic '{}'", client.config.serverHost, client.config.serverPort, topic)
100101

101102
// Create a channel for the topic
@@ -141,7 +142,7 @@ class MqttProtocolClient(
141142

142143

143144
// Function to publish content to a topic and return a response
144-
private suspend fun requestReply(form: Form, content: Content?, topic: String): Content {
145+
private suspend fun requestReply(form: WoTForm, content: Content?, topic: String): Content {
145146
// Generate a unique response topic for this request
146147
val responseTopic = "${topic}/reply/${UUID.randomUUID()}"
147148

@@ -209,8 +210,11 @@ class MqttProtocolClient(
209210
}
210211
}
211212

213+
override fun setCredentialsProvider(credentialsProvider: CredentialsProvider) {
214+
}
215+
212216
// Function to read the resource using the request-reply pattern
213-
override suspend fun readResource(form: Form): Content {
217+
override suspend fun readResource(form: WoTForm): Content {
214218
// Extract the content type from the form or use a default if not provided
215219

216220
// Extract the topic from the URI
@@ -227,7 +231,7 @@ class MqttProtocolClient(
227231
}
228232

229233
// Function to write the resource using the request-reply pattern
230-
override suspend fun writeResource(form: Form, content: Content) {
234+
override suspend fun writeResource(form: WoTForm, content: Content) {
231235
// Extract the topic from the URI
232236
val requestUri = URI(form.href)
233237
val topic = requestUri.path.removePrefix("/") // Removing leading "/"

0 commit comments

Comments
 (0)