Skip to content

Instantly share code, notes, and snippets.

@RigoLigoRLC
Created October 16, 2023 03:36
Show Gist options
  • Save RigoLigoRLC/ee3ce2bebd8fd5079efd7237b08ee53a to your computer and use it in GitHub Desktop.
Save RigoLigoRLC/ee3ce2bebd8fd5079efd7237b08ee53a to your computer and use it in GitHub Desktop.
JLU CAS Login snippet (Does Not Work)
// Build an client that doesn't follow redirect
val okhttpNoRedirect = okhttp.newBuilder()
.followRedirects(false)
.build()
if (!verifyUserCredentials()) {
state._loginState.value = LoginState.NoSessionData
return
}
state._loginState.value = LoginState.LoggingIn
val initialReq = Request.Builder()
.url("https://ehall.jlu.edu.cn")
.get()
.build()
var resp = okhttpNoRedirect.newCall(initialReq).await()
var respBody = ""
var JsessionId = ""
val initialReqCookies = mutableMapOf<String, String>()
Log.i("LOGIN", "First hop: ${resp.code} Redirect: ${resp.isRedirect}")
while (resp.isRedirect) {
// Find JSESSIONID in all the redirects
if (JsessionId == "") {
JsessionId = resp.headers.find {
it.first == "Set-Cookie" && it.second.startsWith("JSESSIONID")
}?.second ?: ""
if (JsessionId != "") {
Log.i("LOGIN", JsessionId)
}
}
// Obtain cookies
resp.headers.forEach {
if (it.first == "Set-Cookie") {
val cookieVal = it.second.substringAfter('=').substringBefore(';')
val cookieName = it.second.substringBefore('=')
initialReqCookies[cookieName] = cookieVal
}
}
// Not hitting cookie? Handle redirects
// if (!loginResp.isSuccessful) {
// Log.e("LOGIN", "Login failed. Code = ${resp.code}, Message = ${resp.message}")
// state._loginState.value = LoginState.LoginFailed
// return
// }
// Redirect
var target = resp.headers["Location"]!!
if (!target.startsWith("https"))
target = "https://${resp.request.url.host}$target"
Log.i("LOGIN", "Resolve redirect ${resp.code} -> $target")
val loginReq = Request.Builder()
.url(target)
.addHeader("Referer", resp.request.url.toString())
.addHeader(
"Cookie",
initialReqCookies.map { "${it.key}=${it.value}; " }
.fold("") { acc, s -> acc + s })
.get()
.build()
resp = okhttpNoRedirect.newCall(loginReq).await()
respBody = AsyncReadResponse(resp.body)
Log.d("LOGIN", respBody)
}
if (!resp.isSuccessful) {
Log.e("LOGIN", "Initial request failed. Code = ${resp.code}, Message = ${resp.message}")
state._loginState.value = LoginState.LoginInternalError
return
}
// We should be getting a login page response here with server side rendered session "lt"
// Find "lt" in response with a simple regex
val ltMatcher = """<input.+id="lt".+value="(.+)".+>""".toRegex()
val ltMatches = ltMatcher.find(respBody)
if (ltMatches == null) {
Log.e("LOGIN", "Cannot match \"lt\"")
state._loginState.value = LoginState.LoginInternalError
return
}
val ltValue = ltMatches.groups[1]!!.value
Log.d("LOGIN", "lt=${ltValue}")
// "execution" is also needed
val execMatcher = """<input.+name="execution".+value="(.+)".+>""".toRegex()
val execMatches = execMatcher.find(respBody)
if (execMatches == null) {
Log.e("LOGIN", "Cannot match \"execution\"")
state._loginState.value = LoginState.LoginInternalError
return
}
val execValue = execMatches.groups[1]!!.value
Log.d("LOGIN", "execution=${execValue}")
// Find where should we post the form to
val postActionMatcher = """<form.+action="(.+)".+>""".toRegex()
val postActionMatches = postActionMatcher.find(respBody)
if (postActionMatches == null) {
Log.e("LOGIN", "Cannot match \"action\"")
state._loginState.value = LoginState.LoginInternalError
return
}
// var postAction = postActionMatches.groups[1]!!.value
// postAction = URLDecoder.decode(postAction, "UTF-8")
// Log.d("LOGIN", "action=${postAction}")
// Concatenate and encrypt
val username = pref.getString("Username", "")!!
val password = pref.getString("Password", "")!!
val encryptValue = username + password + ltValue
val encrypted = crypto.strEnc(encryptValue, "1", "2", "3")
val loginForm = FormBody.Builder()
.add("rsa", encrypted)
.add("ul", username.length.toString())
.add("pl", password.length.toString())
.add("sl", "0")
.add("lt", ltValue)
.add("execution", execValue)
.add("_eventId", "submit")
.build()
val loginHeader = Headers.Builder()
.add("Content-Type", "application/x-www-form-urlencoded")
// .add("Referer", resp.request.url.toString())
// .add(
// "Cookie",
// initialReqCookies.map { "${it.key}=${it.value}; " }
// .fold("") { acc, s -> acc + s })
.build()
val loginReq = Request.Builder()
.url("https://cas.jlu.edu.cn/tpass/login?service=https://ehall.jlu.edu.cn")
.headers(loginHeader)
.post(loginForm)
.build()
// Perform login
var loginResp = okhttp.newCall(loginReq).await()
Log.d("LOGIN", "Login response ${loginResp.code}")
Log.d("LOGIN", AsyncReadResponse(loginResp.body))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment