LDAP Authentication

I am working on an app using LDAP authentication. I have been working on some code I found that allows me to use my existing PHP script. Everything appears to be working. I am getting the proper responses when I enter my network credentials - whether it is a good login or bad one. Right now, I'm just asking it to print "Access Granted" or "Access Denied". However, any attempts to do more - like a pop up window or a segue to a new View Controller crashes the app on the simulator.


Here is my code:

https://youtu.be/SIULwyOpxW8
    func DoLogin(_ user:String, _ psw:String) {
        let url = URL(string: "http://myserver.com/user/check_login_app.php")

        let session = URLSession.shared
    
        let request = NSMutableURLRequest(url: url!)
        request.httpMethod = "POST"
    
        let postString = "username=\(txtUsername.text!)&password=\(txtPassword.text!)"
    
        request.httpBody = postString.data(using: String.Encoding.utf8)
    
        let task = session.dataTask(with: request as URLRequest) {
            data, response, error in
        
            if error != nil {
                return
            }

            let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue)

            if(responseString == "1") {
                self.goodLogin()
            } else if (responseString == "0") {
                self.badLogin()
            }
        
        }       
        task.resume()
    
        txteNumber.text = ""
        txtPassword.text = ""
    
    }

    func goodLogin() {
        print("Access Granted!")
        performSegue(withIdentifier: "loggedIn", sender: self)
    }
    func badLogin() {
        print("Access denied!")

    }


As I stated previously, the app crashes as soon as I add Line #41 to my code.


I am not finding much luck with any searches, so I'm hoping someone can point out what I'm doing wrong. https://youtu.be/zUj04J3KxqI

I suppose you mean line 39.


have you check the name of the segue in storyboard ? It must match exactly the identifier.


If segue is defined programmatically, you need to prepareForSegue in the controller.

The problem here is related to the thread on which your completion handler is run. The vast bulk of UIKit is main thread only. The shared URLSession calls its completion handlers on an unspecified background thread. Thus, when you try to do UI stuff from your completion handler you crash.

You can solve this in two ways:

  • Create your own URLSession object and, when you do, tell it to run the completion handlers on the main thread (by passing in

    OperationQueue.main
    ).
  • In your completion handler, bounce to the main queue with code like this.

DispatchQueue.main.async {
    …
}

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Claude31:


Thank you for the response. Yes. That's exactly right - it is line #39. The name of the segue is "loggedIn". In fact, that's the first thing I checked when all this started happening.


One thing I keep coming back to is that I wonder if what is being returned is not correct. Perhaps the code needs to be changed to interpret the data correctly.

Eskimo:


I've only been playing around with Swift for less than a year now, and I'm still very green at this stuff. That being said, I'm having a difficult time understanding what you posted. The code I posted are pieces from some other code that did something similar to what I'm trying to do - perhaps that's where the break is happening.


Would it be possible to provide me a step by step on what I need to do in order to make this work? The lines of code I provided are the meat of the code, but I've attached a PDF of my entire code. I appreciate any suggestions and assistance.


Thank you.


View Controller

You’re using the shared URLSession (line 5; all the line numbers are going to be relative to the code in your original post). You’re using the URLSession convenience API to create a data task (line 14). That API calls a closure when the task is finished (lines 14 through 28). URLSessions call their delegate methods and completion closures on a specific queue known as the delegate queue. If you have your own session you can specify that queue (via the

delegateQueue
parameter when you create the session), but if you’re use the shared session you have no control. The shared session calls its delegate methods and completion closures on some arbitrary queue. Such a queue is run by a secondary thread.

The problem is that UIKit must be called from the main thread. When your closure calls

goodLogin()
(line 24) which calls
performSegue(withIdentifier:sender:)
(line 39), you’re doing so on a secondary thread and UIKit fails.

There’s two ways you can fix this:

  • Create your own URLSession and set the delegate queue to the main queue. That way your completion closure will run on the main thread and it can call UIKit.

  • Bounces from your completion closure to your main thread via dispatch async. That is, change this:

    let task = session.dataTask(with: request) { data, response, error in      
        … code that calls UIKit …
    }

    to this:

    let task = session.dataTask(with: request) { data, response, error in      
        DispatchQueue.main.async {  
            … code that calls UIKit …
        }  
    }

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
LDAP Authentication
 
 
Q