Jump to content
  • 0

Авторизация на NDMS с помощью curl.


Roundik

Question

Добрый день!

Купил keenetic air, стоит ndms 3.5.1 . 

Требуется сделать реконнект, например с помощью curl.

Ни в какую не получается авторизоваться, шлю {"login":"admin","password":"md5($password)"} на /auth , в чем проблема авторизации, непонятно. Защита яваскрипт какая-то?

Есть готовые решения у кого-нибудь?

Спасибо!

Link to comment
Share on other sites

2 answers to this question

Recommended Posts

  • 0
1 час назад, Roundik сказал:

Добрый день!

Купил keenetic air, стоит ndms 3.5.1 . 

Требуется сделать реконнект, например с помощью curl.

Ни в какую не получается авторизоваться, шлю {"login":"admin","password":"md5($password)"} на /auth , в чем проблема авторизации, непонятно. Защита яваскрипт какая-то?

Есть готовые решения у кого-нибудь?

Спасибо!

 

  • Thanks 1
Link to comment
Share on other sites

  • 0

Т.к. тема с примерами кода закрыта, отправлю сюда вариант на 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
}

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...