Custom Auth using AWS Cognito, Swift - swift

I am trying to use AWS Cognito for password less signin/signup using mobile number.
Signin/Signup steps:
User submits only mobile number
After receiving the passcode via sms, the user submits that to signin/signup.
To achieve the above, as there is no example code for mobile number only Signin, I am trying to amend the standard sign up (email, password) code shown in this aws sdk github example.
Can someone please advice what changes are to be made to achieve signin via mobile number only (no e-mail or username).
import Foundation
import AWSCognitoIdentityProvider
class SignUpViewController: UIViewController {
var pool: AWSCognitoIdentityUserPool?
var sentTo: String?
#IBOutlet weak var username: UITextField!
#IBOutlet weak var password: UITextField!
#IBOutlet weak var phone: UITextField!
#IBOutlet weak var email: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
self.pool = AWSCognitoIdentityUserPool.init(forKey: AWSCognitoUserPoolsSignInProviderKey)
}
override func viewWillAppear(_ animated: Bool) {
self.navigationController?.setNavigationBarHidden(false, animated: false)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let signUpConfirmationViewController = segue.destination as? ConfirmSignUpViewController {
signUpConfirmationViewController.sentTo = self.sentTo
signUpConfirmationViewController.user = self.pool?.getUser(self.username.text!)
}
}
#IBAction func signUp(_ sender: AnyObject) {
guard let userNameValue = self.username.text, !userNameValue.isEmpty,
let passwordValue = self.password.text, !passwordValue.isEmpty else {
let alertController = UIAlertController(title: "Missing Required Fields",
message: "Username / Password are required for registration.",
preferredStyle: .alert)
let okAction = UIAlertAction(title: "Ok", style: .default, handler: nil)
alertController.addAction(okAction)
self.present(alertController, animated: true, completion: nil)
return
}
var attributes = [AWSCognitoIdentityUserAttributeType]()
if let phoneValue = self.phone.text, !phoneValue.isEmpty {
let phone = AWSCognitoIdentityUserAttributeType()
phone?.name = "phone_number"
phone?.value = phoneValue
attributes.append(phone!)
}
if let emailValue = self.email.text, !emailValue.isEmpty {
let email = AWSCognitoIdentityUserAttributeType()
email?.name = "email"
email?.value = emailValue
attributes.append(email!)
}
//sign up the user
self.pool?.signUp(userNameValue, password: passwordValue, userAttributes: attributes, validationData: nil).continueWith {[weak self] (task) -> Any? in
guard let strongSelf = self else { return nil }
DispatchQueue.main.async(execute: {
if let error = task.error as? NSError {
let alertController = UIAlertController(title: error.userInfo["__type"] as? String,
message: error.userInfo["message"] as? String,
preferredStyle: .alert)
let retryAction = UIAlertAction(title: "Retry", style: .default, handler: nil)
alertController.addAction(retryAction)
self?.present(alertController, animated: true, completion: nil)
} else if let result = task.result {
// handle the case where user has to confirm his identity via email / SMS
if (result.user.confirmedStatus != AWSCognitoIdentityUserStatus.confirmed) {
strongSelf.sentTo = result.codeDeliveryDetails?.destination
strongSelf.performSegue(withIdentifier: "confirmSignUpSegue", sender:sender)
} else {
let _ = strongSelf.navigationController?.popToRootViewController(animated: true)
}
}
})
return nil
}
}
}

Related

Ensure phone number UITextField has a "+" prefix

I have several UITextField where a user can insert phone numbers into it. When I click the send button, it sends an automated message to the numbers listed. Everything works well but what I want to do is that when I click on the Send Button, I want it to check if the UITextFields that has text in it has a + symbol in front of the phone number listed before connecting with my server to send the automated message. How do I go about sending an alert to the user if the phone number listed does not have a + symbol?
ViewController:
class ViewController: UIViewController {
#IBOutlet weak var scrollviewcontact: UIScrollView!
#IBOutlet weak var viewcontact: UIView!
#IBOutlet weak var phonenumber: UITextField!
#IBOutlet weak var phonenumber1: UITextField!
#IBOutlet weak var phonenumber2: UITextField!
#IBOutlet weak var phonenumber3: UITextField!
var currentTextField: UITextField?
private let contactPicker = CNContactPickerViewController()
override func viewDidLoad() {
super.viewDidLoad()
phonenumber.textContentType = .telephoneNumber
phonenumber1.textContentType = .telephoneNumber
phonenumber2.textContentType = .telephoneNumber
phonenumber3.textContentType = .telephoneNumber
}
#IBAction func sendbutton(_ sender: Any) {
var numArray: Array<Any>
numArray = [phonenumber.text!, phonenumber1.text!, phonenumber2.text!, phonenumber3.text!]
let Url = String(format: "//URL")
guard let serviceUrl = URL(string: Url) else { return }
var request = URLRequest(url: serviceUrl)
request.httpMethod = "POST"
request.setValue("Application/json", forHTTPHeaderField: "Content-Type")
guard let httpBody = try? JSONSerialization.data(withJSONObject: numArray, options:[]) else {
return
}
request.httpBody = httpBody
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if let response = response {
print(response)
}
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments)
print("json ", json)
} catch {
print(error)
}
}
}.resume()
}
extension ViewController: CNContactPickerDelegate {
func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
let phoneNumberCount = contact.phoneNumbers.count
guard phoneNumberCount > 0 else {
dismiss(animated: true)
return
}
if phoneNumberCount == 1 {
setNumberFromContact(contactNumber: contact.phoneNumbers[0].value.stringValue)
}else{
let alertController = UIAlertController(title: "Select one of the numbers", message: nil, preferredStyle: .alert)
for i in 0...phoneNumberCount-1 {
let phoneAction = UIAlertAction(title: contact.phoneNumbers[i].value.stringValue, style: .default, handler: {
alert -> Void in
self.setNumberFromContact(contactNumber: contact.phoneNumbers[i].value.stringValue)
})
alertController.addAction(phoneAction)
}
let cancelAction = UIAlertAction(title: "Cancel", style: .destructive, handler: {
alert -> Void in
})
alertController.addAction(cancelAction)
dismiss(animated: true)
self.present(alertController, animated: true, completion: nil)
}
}
func setNumberFromContact(contactNumber: String) {
var contactNumber = contactNumber.replacingOccurrences(of: "-", with: "")
contactNumber = contactNumber.replacingOccurrences(of: "(", with: "")
contactNumber = contactNumber.replacingOccurrences(of: ")", with: "")
contactNumber = contactNumber.replacingOccurrences(of: " ", with: "")
currentTextField?.text = String(contactNumber)
}
func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
}
}
The goal that I'm trying to achieve is that when the Send Button is clicked, it checks which UITextField has text in it, and if it doesn't have a + as a prefix, an alert message should pop up.
You can try
let numArray = [phonenumber.text!, phonenumber1.text!, phonenumber2.text!, phonenumber3.text!]
guard numArray.filter { $0.hasPrefix("+") }.count == numArray.count else {
// alert with message make sure all textfields has + prefix
return
}
You can use the hasPrefix method. For example:
for num in numArray {
if num.hasPrefix("+") {
// do something
} else {
// do something else
}
}

objc[75927]: Class PFFile and objc[75927]: Class PFLogger is implemented in both One of the two will be used. Which one is undefined

No errors in my code, but the console is printing the title of this post. I am using parse as a server. I am using this exact same code in an example video that i learned from on Udemy. Also None of my buttons are working when they are connected properly.
import UIKit
import Parse
class ViewController: UIViewController {
var signUpMode = true
var activityIndicator = UIActivityIndicatorView()
#IBOutlet var emailTextField: UITextField!
#IBOutlet var passwordTextField: UITextField!
#IBOutlet var signUpOrLogin: UIButton!
#IBOutlet var changeSignUpMode: UIButton!
#IBOutlet var messageLabel: UILabel!
func createAlert(title:String, message: String) {
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action) in
//self.dismiss(animated: true, completion: nil)
}))
self.present(alert, animated: true, completion: nil)
}
#IBAction func signUpOrLogin(_ sender: Any) {
if emailTextField.text == "" || passwordTextField.text == "" {
createAlert(title: "Error due to form", message: "Please enter an Email and Password.")
} else {
activityIndicator = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
activityIndicator.center = self.view.center
activityIndicator.hidesWhenStopped = true
activityIndicator.style = UIActivityIndicatorView.Style.gray
view.addSubview(activityIndicator)
activityIndicator.startAnimating()
UIApplication.shared.beginIgnoringInteractionEvents()
if signUpMode{
let user = PFUser()
user.username = emailTextField.text
user.email = emailTextField.text
user.password = passwordTextField.text
user.signUpInBackground(block:{ (success, error) in
self.activityIndicator.stopAnimating()
UIApplication.shared.endIgnoringInteractionEvents()
if error != nil {
var displayErrorMessage = "Please try again later"
if let errorMessage = (error! as NSError).userInfo["error"] as? String {
displayErrorMessage = errorMessage
//This is the message that the console gives us
}
self.createAlert(title: "Signup Error", message: displayErrorMessage)
} else {
print("user signed up")
}
})
} else {
//login mode
PFUser.logInWithUsername(inBackground: emailTextField.text!, password: passwordTextField.text!) { (user, error) in
self.activityIndicator.stopAnimating()
UIApplication.shared.endIgnoringInteractionEvents()
if error != nil{
var displayErrorMessage = "Please try again later"
if let errorMessage = (error! as NSError).userInfo["error"] as? String {
displayErrorMessage = errorMessage
//This is the message that the console gives us
}
self.createAlert(title: "Login Error", message: displayErrorMessage)
} else {
print("logged in")
}
}
}
}
}
#IBAction func changeSignUpMode(_ sender: Any) {
if signUpMode{
//Change to Login Mode
signUpOrLogin.setTitle("Log In", for: [] ) //empty array is default state again....
changeSignUpMode.setTitle("Sign Up", for: [])
messageLabel.text = "Don't have an account?"
signUpMode = false
} else {
//Change to SignupMode
signUpOrLogin.setTitle("Sign Up", for: [])
changeSignUpMode.setTitle("Log In", for: [])
messageLabel.text = "Already have an account?"
signUpMode = true
}
}

use of unresolved identifier 'result' swift 3

I'm writing a login page for my app and i'm getting this error
social media app , xcode 8.3.2 , swift 3
i've tried target membership in file inspector and nothing changed
also I removed test units (UITest and Test) and renew them , it didn't worked either.
at the line 41 I'm getting this error "use of unresolved identifier 'result'"
the picture below explains the code
Picture
import UIKit
class LoginViewController : UIViewController
{
#IBOutlet weak var txt_username: UITextField!
#IBOutlet weak var txt_password: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func btn_log_in_click(_ sender: Any){
let server=MultipartUtility (Url:"http://x.x.x.x/appname-api/user/login/")
//I.m hiding the real ip and details for posting this
server.AddFormField("username", value: txt_username.text)
server.AddFormField("password", value: txt_password.text)
let task = URLSession.shared.dataTask(with: server.execute())
{Data,URLResponse,error in
if error != nil{
print(error as Any)
return
}
do{
let json = try JSONSerialization.jsonObject(with: Data!, options: .allowFragments)
if let json_result = json as? [String: Any]{
let result = json_result ["result"] as? String
if result == "0"
{
DispatchQueue.main.async {
let alert = UIAlertController(title:"Incorrect Username",message : "The username you entered doesn't appear to belong to an account. Please check your username and try again", preferredStyle : .alert)
let alert_action = UIAlertAction(title: "Try Again", style: .default, handler: nil)
alert.addAction(alert_action)
self.present(alert, animated: true, completion: nil)
}
}
}
else{
DispatchQueue.main.async {
UserDefaults.standard.set(result!, forKey: "user_id")
//" use of unresolved identifier 'result' "
let current_view=UIApplication.shared.windows[0] as UIWindow
let new_view=(self.storyboard? .instantiateViewController(withIdentifier: "tab_bar"))! as UIViewController
UIView.transition(from: (current_view.rootViewController? .view)!, to:new_view.view , duration: 0.65, options: .transitionFlipFromRight, completion: {(action) in current_view.rootViewController=new_view
})
}
}
}
catch{
}
}
task.resume()
}
}
if let json_result = json as? [String: Any]
{
let result = json_result ["result"] as? String
if result == "0"
{
DispatchQueue.main.async {
let alert = UIAlertController(title:"Incorrect Username",message : "The username you entered doesn't appear to belong to an account. Please check your username and try again", preferredStyle : .alert)
let alert_action = UIAlertAction(title: "Try Again", style: .default, handler: nil)
alert.addAction(alert_action)
self.present(alert, animated: true, completion: nil)
}
}
else
{
DispatchQueue.main.async {
UserDefaults.standard.set(result!, forKey: "user_id")
//" use of unresolved identifier 'result' "
let current_view=UIApplication.shared.windows[0] as UIWindow
let new_view=(self.storyboard? .instantiateViewController(withIdentifier: "tab_bar"))! as UIViewController
UIView.transition(from: (current_view.rootViewController? .view)!, to:new_view.view , duration: 0.65, options: .transitionFlipFromRight, completion: {(action) in current_view.rootViewController=new_view
})
}
}
}
else{
// Error in jsonSerialization
}

"use of unresolved identifier 'myAlert & okAction'

I keep receiving an error on 15th and 16th lines from the bottom. It tells me:
"use of unresolved identifier 'myAlert & okAction'"
If anyone can help, it would be much appreciated.
Code:
import UIKit
class RegisterPageViewController: UIViewController {
#IBOutlet weak var userNameTextField: UITextField!
#IBOutlet weak var userPhoneTextField: UITextField!;
#IBOutlet weak var userPasswordTextField: UITextField!;
#IBOutlet weak var userConfirmPasswordTextField: UITextField!;
#IBOutlet weak var userPlugTextField: UITextField!;
#IBAction func RegisterButtonTapped(_ sender: Any) {
let userName = userNameTextField.text;
let userPhone = userPhoneTextField.text;
let userPassword = userPasswordTextField.text;
let userConfirmPassword = userConfirmPasswordTextField.text;
let userPlug = userPlugTextField.text;
// Check for empty fields
if(userName!.isEmpty || userPhone!.isEmpty || userPassword!.isEmpty || userConfirmPassword!.isEmpty || userPlug!.isEmpty)
{
displayMyAlertMessage(userMessage: "All fields are required")
return;
}
// check if passwords match
if(userPassword != userConfirmPassword)
{
// Display an alert message
displayMyAlertMessage(userMessage: "Passwords do not match")
return;
}
// Store data
UserDefaults.standard.set(userName, forKey: "userName")
UserDefaults.standard.set(userName, forKey: "userPhone")
UserDefaults.standard.set(userName, forKey: "userPassword")
UserDefaults.standard.set(userName, forKey: "userPlug")
UserDefaults.standard.synchronize();
// Display alert message with confirmation
_ = UIAlertController(title:"Alert", message:"Registration is successful. Thank you!", preferredStyle: UIAlertControllerStyle.alert);
_ = UIAlertAction(title:"Ok", style: UIAlertActionStyle.default){ action in
self.dismiss(animated: true, completion:nil)
}
myAlert.addAction(okAction);
self.present(myAlert, animated:true, completion:nil)
}
func displayMyAlertMessage(userMessage:String)
{
let myAlert = UIAlertController(title:"Alert", message:userMessage, preferredStyle: UIAlertControllerStyle.alert);
let okAction = UIAlertAction(title:"Ok", style: UIAlertActionStyle.default, handler:nil);
myAlert.addAction(okAction);
self.present(myAlert, animated:true, completion:nil);
}
}
Replace
_ = UIAlertController(title:"Alert", message:"Registration is successful. Thank you!", preferredStyle: UIAlertControllerStyle.alert);
_ = UIAlertAction(title:"Ok", style: UIAlertActionStyle.default){ action in
self.dismiss(animated: true, completion:nil)
}
with
let myAlert = UIAlertController(title:"Alert", message:"Registration is successful. Thank you!", preferredStyle: UIAlertControllerStyle.alert);
let okAction = UIAlertAction(title:"Ok", style: UIAlertActionStyle.default){ action in
self.dismiss(animated: true, completion:nil)
}
You cannot 'see' those two objects because you are trying to reference them outside of their scope. Their scope is the function in which they are defined.
Not sure why you have those two lines at all, though, if you have
displayMyAlertMessage(userMessage:)

Password is getting cached somewhere, need to clear it

I am working on an app that accesses a REST API Webservice. Everything is working great, except I recently started working on the the ability to logout and switch users and I've run into a strange situation. If I log out, and then click login again without entering the password it's working. I've even debugged the code and see that the password is blank, but the authentication is still working. Here is the code:
import UIKit
import LocalAuthentication
var userName = String()
var password = String()
var server = String()
var port = String()
var myUser = User()
var myExtensions = [ExtensionListItem]()
var myDevices = [Device]()
class LoginViewController: UIViewController, NSURLSessionDelegate, UITextFieldDelegate {
let authContext: LAContext = LAContext()
var logOutUser = Bool()
#IBOutlet weak var activityIndicator: UIActivityIndicatorView!
#IBOutlet weak var serverNameField: UITextField!
#IBOutlet weak var usernameField: UITextField!
#IBOutlet weak var passwordField: UITextField!
#IBOutlet var loginEnable: UIButton!
var userPasswordString = NSString()
let userRequest = NSMutableURLRequest()
var userSession = NSURLSession()
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(logoff), name: "logoff", object: nil)
if logOutUser {
NSUserDefaults.standardUserDefaults().setValue("", forKey: "password")
NSURLCache.sharedURLCache().removeAllCachedResponses()
userPasswordString = NSString()
}
//Determine if the user has a stored Username and populate the usernameField if possible
if NSUserDefaults.standardUserDefaults().objectForKey("userName") != nil{
usernameField.text = NSUserDefaults.standardUserDefaults().objectForKey("userName") as? String}
//Determine if the user has a stored ServerName and populate the serverNameField if possible.
if NSUserDefaults.standardUserDefaults().objectForKey("serverName") != nil{
serverNameField.text = NSUserDefaults.standardUserDefaults().objectForKey("serverName") as? String}
//Determin if the user has requested to use Touch ID
if (NSUserDefaults.standardUserDefaults().objectForKey("useTouchID") != nil) {
if NSUserDefaults.standardUserDefaults().valueForKey("useTouchID") as! Bool == true && CheckTouchIDCapable(){
//Trigger Touch ID
usernameField.enabled = false
passwordField.enabled = false
serverNameField.enabled = false
activityIndicator.startAnimating()
TouchIDCall()
}
}
// Do any additional setup after loading the view.
}
func logoff(){
NSURLCache.sharedURLCache().removeAllCachedResponses()
userSession.invalidateAndCancel()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
NSURLCache.sharedURLCache().removeAllCachedResponses()
// Dispose of any resources that can be recreated.
}
#IBAction func loginButton(sender: AnyObject) {
NSUserDefaults.standardUserDefaults().setObject(usernameField.text, forKey: "userName")
NSUserDefaults.standardUserDefaults().setObject(passwordField.text, forKey: "password")
NSUserDefaults.standardUserDefaults().setObject(serverNameField.text, forKey: "serverName")
if NSUserDefaults.standardUserDefaults().valueForKey("touchIDPreferenceSet") == nil && CheckTouchIDCapable() {
DisplayTouchIDQuestion("Use Touch ID?", message: "Would you like to use touch ID to login?")
}else{
usernameField.enabled = false
passwordField.enabled = false
serverNameField.enabled = false
activityIndicator.startAnimating()
CheckUser()
}
print("Password: \(password)")
print("Stored Password: \(NSUserDefaults.standardUserDefaults().valueForKey("password"))")
print("?? \(NSUserDefaults.standardUserDefaults().objectForKey("password"))")
}
func CheckUser(){
userName = (NSUserDefaults.standardUserDefaults().objectForKey("userName") as? String)!
if !logOutUser{
password = (NSUserDefaults.standardUserDefaults().objectForKey("password") as? String)!
}
server = (NSUserDefaults.standardUserDefaults().objectForKey("serverName") as? String)!
port = "8443"
// set up the base64-encoded credentials
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
userPasswordString = NSString(format: "%#:%#", userName, password)
let userPasswordData = userPasswordString.dataUsingEncoding(NSUTF8StringEncoding)
let base64EncodedCredential = userPasswordData!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
let authString = "Basic \(base64EncodedCredential)"
config.HTTPAdditionalHeaders?.removeAll()
config.HTTPAdditionalHeaders = ["Authorization" : authString]
config.timeoutIntervalForRequest = 10.0
// create the user request
let userUrlString = NSString(format: "https://%#:%#/webserver/user/%#", server, port, userName)
let userUrl = NSURL(string: userUrlString as String)
userRequest.cachePolicy = .ReloadIgnoringLocalAndRemoteCacheData
userRequest.URL = userUrl!
userRequest.HTTPMethod = "GET"
userRequest.setValue("Basic \(base64EncodedCredential)", forHTTPHeaderField: "Authorization")
userSession = NSURLSession(configuration: config, delegate: self, delegateQueue:NSOperationQueue.mainQueue())
//Send User Request to the server and populate labels with response.
_ = userSession.dataTaskWithRequest(userRequest) { (data, response, error) in
dispatch_async(dispatch_get_main_queue(), { () -> Void in
if error?.code != nil{
print("ERROR: \(error!.localizedDescription)")
self.DisplayAlert("Error", message: error!.localizedDescription)
}else{
_ = NSString (data: data!, encoding: NSUTF8StringEncoding)
let dataString = NSString(data: data!, encoding: NSUTF8StringEncoding)
let accessDenied = Bool(dataString?.rangeOfString("HTTP Status 403").location != NSNotFound)
let authFailure = Bool(dataString?.rangeOfString("HTTP Status 401").location != NSNotFound)
if (authFailure || accessDenied) {
print("\(NSDate()): Unsuccessful Password Authentication Attempt for user: \(NSUserDefaults.standardUserDefaults().valueForKey("userName")!)")
self.DisplayAlert("Access Denied", message: "Please Verify Your Credentials")
}else{
print("\(NSDate()): Successful Password Authentication for user: \(NSUserDefaults.standardUserDefaults().valueForKey("userName")!)")
self.performSegueWithIdentifier("authenticated", sender: self)
}
}
})
}.resume()
}
func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!))
}
override func prefersStatusBarHidden() -> Bool {
return true
}
// MARK: - Keyboard Functions
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.view.endEditing(true)
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
if textField == passwordField && usernameField.text != "" && serverNameField.text != ""{
loginButton(self)
}
return true
}
func ReEnableLogin(){
self.activityIndicator.hidesWhenStopped = true
self.activityIndicator.stopAnimating()
self.usernameField.enabled = true
self.passwordField.enabled = true
self.serverNameField.enabled = true
}
func DisplayAlert(title: String, message: String){
let alertController = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alertController, animated: true, completion: nil)
self.ReEnableLogin()
}
func DisplayTouchIDQuestion(title: String, message: String){
let alertControllerQuestion = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
alertControllerQuestion.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.Default, handler: { (action:UIAlertAction) in
NSUserDefaults.standardUserDefaults().setValue(true, forKey: "useTouchID")
NSUserDefaults.standardUserDefaults().setValue(true, forKey: "touchIDPreferenceSet")
NSUserDefaults.standardUserDefaults().setValue(self.passwordField.text, forKey: "touchIDCachedCredential")
self.CheckUser()
}))
alertControllerQuestion.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.Default, handler: { (action:UIAlertAction) in
NSUserDefaults.standardUserDefaults().setValue(false, forKey: "useTouchID")
NSUserDefaults.standardUserDefaults().setValue(true, forKey: "touchIDPreferenceSet")
self.CheckUser()
}))
self.presentViewController(alertControllerQuestion, animated: true, completion: nil)
}
func CheckTouchIDCapable()-> Bool {
var error: NSError?
var touchEnabledDevice: Bool = false
if authContext.canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, error: &error){
touchEnabledDevice = true
}
return touchEnabledDevice
}
func TouchIDCall(){
authContext.evaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason: "Place your finger on the Home button to log into Collaboration User Tools", reply: { (wasSuccessful, error) in
if wasSuccessful{
print("\(NSDate()): Successful Biometric Authentication for user: \(NSUserDefaults.standardUserDefaults().valueForKey("userName")!)")
NSUserDefaults.standardUserDefaults().setValue(NSUserDefaults.standardUserDefaults().valueForKey("touchIDCachedCredential"), forKey: "password")
self.CheckUser()
}else{
print("\(NSDate()): Error: \(error!.code)")
print("\(NSDate()): Unsuccessful Biometric Authentication for user: \(NSUserDefaults.standardUserDefaults().valueForKey("userName")!)")
let qualityOfServiceClass = QOS_CLASS_USER_INTERACTIVE
let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
dispatch_async(backgroundQueue, {
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.activityIndicator.stopAnimating()
})
})
self.ReEnableLogin()
}
})
}
}
I've tried:
NSURLCache.sharedURLCache().removeAllCachedResponses()
userSession.invalidatedAndCancel()
The logout table view controller calls this method:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
switch indexPath.row{
case 0:
myUser = User()
myExtensions.removeAll()
myDevices.removeAll()
NSUserDefaults.standardUserDefaults().setObject("", forKey: "password")
userName = ""
password = ""
NSURLCache.sharedURLCache().removeAllCachedResponses()
NSNotificationCenter.defaultCenter().postNotificationName("logoff", object: nil)
performSegueWithIdentifier("logout", sender: self)
default:
break
}
}
I don't know where the password is being cached. Any ideas?
I think your issue lies on part of your logic when handling your password. First, in your func CheckUser() you assign the value of var password if !logOutUser from your user defaults, however this property (password) is not getting cleared at any point, so if !logOutUser is false (which it looks like always is, as its not getting set anywhere), and your input fields are empty, then it will use the previous value that you had store in there.
So if I am correct, and the culprit here is that the password field is storing its data, a quick, dirty fix would be to simply clear these fields (username and password) after you perform your request. A better fix would be to directly pass the usernameField.text value directly and clear it after its done. (I'm unsure why you are storing your user's password in your app, which I would recommend reconsidering, if you need it for validating a session you should be using authentication tokens)
// set up the base64-encoded credentials
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
userPasswordString = NSString(format: "%#:%#", userName, password)
userName = ""
password = ""
I would also like to point out that you should be using optionals for these fields, you should be using optional unwrapping for your user defaults and also adding a validation mechanism so that you do not submit requests with empty fields, ideally your button would be disabled or you would alert your user of an invalid field.
Good Luck!
EDIT
Try this approach: rather than using a class property for the values of password username and server. Use method variables to set your values, this way these values will get disposed when the method terminates. (This is a bit of a shot in the dark as i dont have a compiler at hand so there might be some minor syntax errors). - note the method signature
func CheckUser(username: String, password: String, server: String){
let port = "8443"
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let userPasswordString = NSString(format: "%#:%#", username, password)
let userPasswordData = userPasswordString.dataUsingEncoding(NSUTF8StringEncoding)
let base64EncodedCredential = userPasswordData!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
let authString = "Basic \(base64EncodedCredential)"
config.HTTPAdditionalHeaders?.removeAll()
config.HTTPAdditionalHeaders = ["Authorization" : authString]
config.timeoutIntervalForRequest = 10.0
// create the user request
let userUrlString = NSString(format: "https://%#:%#/webserver/user/%#", server, port, username)
let userUrl = NSURL(string: userUrlString as String)
userRequest.cachePolicy = .ReloadIgnoringLocalAndRemoteCacheData
userRequest.URL = userUrl!
userRequest.HTTPMethod = "GET"
userRequest.setValue("Basic \(base64EncodedCredential)", forHTTPHeaderField: "Authorization")
userSession = NSURLSession(configuration: config, delegate: self, delegateQueue:NSOperationQueue.mainQueue())
//Send User Request to the server and populate labels with response.
let task = userSession.dataTaskWithRequest(userRequest) { (data, response, error) in
dispatch_async(dispatch_get_main_queue(), { () -> Void in
if error?.code != nil{
print("ERROR: \(error!.localizedDescription)")
self.DisplayAlert("Error", message: error!.localizedDescription)
}else{
_ = NSString (data: data!, encoding: NSUTF8StringEncoding)
let dataString = NSString(data: data!, encoding: NSUTF8StringEncoding)
let accessDenied = Bool(dataString?.rangeOfString("HTTP Status 403").location != NSNotFound)
let authFailure = Bool(dataString?.rangeOfString("HTTP Status 401").location != NSNotFound)
if (authFailure || accessDenied) {
print("\(NSDate()): Unsuccessful Password Authentication Attempt for user: \(NSUserDefaults.standardUserDefaults().valueForKey("userName")!)")
self.DisplayAlert("Access Denied", message: "Please Verify Your Credentials")
}else{
print("\(NSDate()): Successful Password Authentication for user: \(NSUserDefaults.standardUserDefaults().valueForKey("userName")!)")
self.performSegueWithIdentifier("authenticated", sender: self)
}
}
})
}.resume()
}
Then you can call your method as so:
if NSUserDefaults.standardUserDefaults().valueForKey("touchIDPreferenceSet") == nil && CheckTouchIDCapable() {
DisplayTouchIDQuestion("Use Touch ID?", message: "Would you like to use touch ID to login?")
}else{
usernameField.enabled = false
passwordField.enabled = false
serverNameField.enabled = false
activityIndicator.startAnimating()
CheckUser(usernameField.text, password: passwordField.text, server: serverNameField.text)
}
My problem was never related to password caching. Most likely due to my relatively amateur experience level, I never considered the fact that it might be COOKIES keeping the session up. That's exactly what it ended up being. I solved the situation simply by deleting all cookies during the logout procedure. I added the following to my logout code and it's working perfectly.
print("\(NSDate()): Logout Requested, Deleting Cookies")
let cookieStorage = NSHTTPCookieStorage.sharedHTTPCookieStorage()
let cookies = cookieStorage.cookies! as [NSHTTPCookie]
print("\(NSDate()): Cookie count: \(cookies.count)")
for cookie in cookies{
print("\(NSDate()): Deleting Cookie name: \(cookie.name) value: \(cookie.value)")
NSHTTPCookieStorage.sharedHTTPCookieStorage().deleteCookie(cookie)
}