Created
October 16, 2023 03:36
-
-
Save RigoLigoRLC/ee3ce2bebd8fd5079efd7237b08ee53a to your computer and use it in GitHub Desktop.
JLU CAS Login snippet (Does Not Work)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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