SwiftUI URLSession login to ASP.net login form difficulties

49 Views Asked by At

Good afternoon everyone, I'm creating an IOS Application which is heavily dependant on a ASP.net website. The website is a roster site and all assignments site. Currently on my main View there is a button called Fetch Data. Whenever that button is pressed I'm trying to run a LogOn function which tries to login to the website. The parameters needed are included in the Post Request. However I'm having the following challenge. The website expects a ViewState to be submitted with the post request. Whenever I'm sending the GET and shortly after the POST request the view state extracted from the GET does not match the expected view state needed for the website. If anybody could point me in the right direction that would be amazing.

func loginToASPNet() {
    guard let url = URL.loginURL else {
        return
        print("Invalid URL") 
    } 
    let config = URLSessionConfiguration.default
    config.timeoutIntervalForRequest = 30 
    config.httpShouldSetCookies = true
    let sessionTask = URLSession(configuration: config) 
    var request = URLRequest(url: url) 
    request.setValue("text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", forHTTPHeaderField: "Accept")
    request.setValue("gzip, deflate, br", forHTTPHeaderField: "Accept-Encoding")
    request.setValue("en-GB,en-US;q=0.9,en;q=0.8", forHTTPHeaderField: "Accept-Language") 
    request.setValue("keep-alive", forHTTPHeaderField: "Connection")
    if let cookies = HTTPCookieStorage.shared.cookies(for: url) {
        let headers = HTTPCookie.requestHeaderFields(with: cookies)
        request.allHTTPHeaderFields = headers
        print(headers) 
    } 
    
    sessionTask.dataTask(with: request) { data, response, error in
        if let error = error { 
            print(error.localizedDescription) 
            return
        }
        
        guard let httpResponse = response as? HTTPURLResponse else {
            return
            print("Invalid Response")
        }
        
        guard let data = data, let htmlString = String(data: data, encoding: .utf8) else {
            return
            print("No data received.") 
        }
        
        do {
            let doc = try SwiftSoup.parse(htmlString) 
            let viewState = try doc.select("input[name=__VIEWSTATE]").val() 
            guard let url = crpURL.loginURL else {
                return
                print("Invalid URL") 
            }
            
            let config = URLSessionConfiguration.default
            config.timeoutIntervalForRequest = 30
            config.httpShouldSetCookies = true
            let sessionTask = URLSession(configuration: config) 
            var postRequest = URLRequest(url: url)
            postRequest.httpMethod = "POST" 
            var components = URLComponents() 
            components.queryItems = [
                URLQueryItem(name: "__LASTFOCUS", value: ""),
                URLQueryItem(name: "__VIEWSTATE", value: viewState), 
                URLQueryItem(name: "__VIEWSTATEGENERATOR", value: "521EEB84"),
                URLQueryItem(name: "__EVENTTARGET", value: ""),
                URLQueryItem(name: "__EVENTARGUMENT", value: ""),
                URLQueryItem(name: "_login:ctrlUserName", value: "exampleUsername"), 
                URLQueryItem(name: "_login:ctrlPassword", value: "examplePassword"), 
                URLQueryItem(name: "_login:btnLogin", value: "Login")
            ] 
            
            postRequest.httpBody = components.query?.data(using: .utf8) 
            postRequest.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") 
            postRequest.setValue("text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", forHTTPHeaderField: "Accept")
            postRequest.setValue("gzip, deflate, br", forHTTPHeaderField: "Accept-Encoding")
            postRequest.setValue("en-GB,en-US;q=0.9,en;q=0.8", forHTTPHeaderField: "Accept-Language")
            postRequest.setValue("keep-alive", forHTTPHeaderField: "Connection") 
            
            if let cookies = HTTPCookieStorage.shared.cookies(for: url) {
                let headers = HTTPCookie.requestHeaderFields(with: cookies) 
                request.allHTTPHeaderFields = headers
                print(headers)
            }
            
            sessionTask.dataTask(with: postRequest) { data, response, error in
                if let error = error {
                    print("Error: \(error.localizedDescription)") 
                }
                
                if let httpResponse = response as? HTTPURLResponse {
                    print("DEBUG LOGIN STATUS CODE \(httpResponse.statusCode)") 
                }
                
                guard let data = data, let htmlString = String(data: data, encoding: .utf8) else {
                    return
                }
                
                do { 
                    let pString = try SwiftSoup.parse(htmlString) 
                    print(pString)
                } catch { }
            }.resume() 
        } catch {
            print("Something went wrong here")
        } 
    }.resume()
} 

With this function I'm sending a GET request to the URL, afterwards if there are cookies to be set I'm setting the Cookies into HTTPCookieStorage. Then using SwiftSoup I'm parsing through the HTML in order to extract the View State. Thereafter I'm creating a post request with the needed Headers (cookies etc) and needed login parameters. The earlier extracted View State I'm injecting in the post request. For some reason after running this code I'm getting redirected back to the login screen. I tried debugging this in Chromes Developer tools in order to see the login payload. The login payload found there is as follows:

__LASTFOCUS: __VIEWSTATE: VERY long string __VIEWSTATEGENERATOR: some ident code __EVENTTARGET: __EVENTARGUMENT: _login:ctrlUserName: exampleUsername _login:ctrlPassword: examplePassword _login:btnLogin: Login

So, currently I'm quite stuck.

0

There are 0 best solutions below