Jump to content

fesswood

Forum Members
  • Posts

    1
  • Joined

  • Last visited

Posts posted by fesswood

  1. Т.к. тема с примерами кода закрыта, отправлю сюда вариант на Kotlin + Ktor (gist):

    import kotlinx.serialization.Serializable
    import io.ktor.http.*
    import java.security.MessageDigest
    import java.util.*
    import io.ktor.client.*
    import io.ktor.client.engine.cio.*
    import io.ktor.client.features.*
    import io.ktor.client.features.cookies.*
    import io.ktor.client.features.json.*
    import io.ktor.client.features.json.serializer.*
    import io.ktor.client.features.logging.*
    import io.ktor.client.request.*
    import io.ktor.client.statement.*
    import io.ktor.http.*
    import kotlinx.coroutines.runBlocking
      
    private const val LOGIN = "login"
    private const val PASSWORD = "password"    
      
    data class KeeneticAuthHeaderValues(
        val map: Map<KeeneticAuthHeaderEnum, String>
    ) {
        val xndmChallenge: String by lazy { map.getValue(KeeneticAuthHeaderEnum.XNDMChallenge) }
        val xndmRealm: String by lazy { map.getValue(KeeneticAuthHeaderEnum.XNDMRealm) }
    }
    
    @Serializable
    data class UserCredentials(val login: String, val password: String)
      
    fun Headers.asMap(): EnumMap<KeeneticAuthHeaderEnum, String> = EnumMap(
        entries().asSequence()
            .filter { it -> it.key in KeeneticAuthHeaderEnum.values().map { it.title } }
            .associate { header -> KeeneticAuthHeaderEnum.from(header.key) to header.value.first() }
    )
    
    // However, here we have to use a custom byte to hex converter to get the hashed value in hexadecimal
    private fun printHexBinary(hash: ByteArray): String {
        val hexString = StringBuilder(2 * hash.size)
        for (i in hash.indices) {
            val hex = Integer.toHexString(0xff and hash[i].toInt())
            if (hex.length == 1) {
                hexString.append('0')
            }
            hexString.append(hex)
        }
        return hexString.toString()
    }
    
    fun String.encodeMd5(): String {
        return printHexBinary(MessageDigest.getInstance("MD5").digest(toByteArray()))
    }
    
    // see more https://www.baeldung.com/sha-256-hashing-java
    fun String.encodeSha256(): String {
    // Java provides inbuilt MessageDigest class for SHA-256 hashing
        return printHexBinary(MessageDigest.getInstance("SHA-256").digest(toByteArray()))
    }
    
    fun main() = runBlocking {
        // HttpClientEngineFactory using a Coroutine based I/O implementation
        val client = HttpClient(CIO) {
            install(JsonFeature) {
                serializer = KotlinxSerializer(kotlinx.serialization.json.Json {
                    ignoreUnknownKeys = true
                    prettyPrint = true
                    isLenient = true
                })
            }
            //log all requests
            install(Logging) {
                logger = Logger.DEFAULT
                level = LogLevel.ALL
            }
            install(HttpCookies) {
                // Will keep an in-memory map with all the cookies from previous requests.
                storage = AcceptAllCookiesStorage()
            }
        }
        // try with resource kotlin way
        client.use {
            // do auth
            authorized(client) {
                // here we have authorize
                val interfaceInfo: HttpResponse = client.get("http://192.168.1.1/rci/show/interface?name=ISP")
            }
    
        }
    
    }
    
    private suspend fun authorized(client: HttpClient, body: suspend () -> Unit) {
        val unauthorizedResponse = client.get<HttpResponse>("http://192.168.1.1/auth") { expectSuccess = false }
    
        if (unauthorizedResponse.status == HttpStatusCode.Unauthorized) {
            val tokenAndRealm = KeeneticAuthHeaderValues(unauthorizedResponse.headers.asMap())
            val authPostResponse = authRequest(client, tokenAndRealm, LOGIN, PASSWORD)
            if (authPostResponse.status == HttpStatusCode.OK) {
                body()
            }
        } else if(unauthorizedResponse.status == HttpStatusCode.OK){
            body()
        }
    }
    
    private suspend fun authRequest(
        client: HttpClient,
        tokenAndRealm: KeeneticAuthHeaderValues,
    ): HttpResponse {
        val authPostResponse = client.post<HttpResponse>("http://192.168.1.1/auth") {
            contentType(ContentType.Application.Json)
            expectSuccess = false
            val md5 = (LOGIN + ":" + tokenAndRealm.xndmRealm + ':' + PASSWORD).encodeMd5()
            body = UserCredentials(
                login = LOGIN,
                password = (tokenAndRealm.xndmChallenge + md5).encodeSha256()
            )
        }
        return authPostResponse
    }

     

×
×
  • Create New...