objective-c clear NSURLCredential - NSURLCredentialPersistenceForSession
Asked Answered
C

2

11

I am using NSURLCredentials in this method:

-(void)UserLogin:(NSString *)user andPassWordExists:(NSString *)password completionHandler:(void (^)(NSArray *resultsObject, NSError *error))completionHandler
{


   NSURL *url = [NSURL URLWithString:kIP];
   NSURLRequest *request = [NSURLRequest requestWithURL:url];

    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]
                                         initWithRequest:request];


    NSURLCredential *credential = [NSURLCredential
                                   credentialWithUser:user
                                   password:password
                                   persistence:NSURLCredentialPersistenceForSession];

    [operation setCredential:credential];

    [[NSOperationQueue mainQueue] addOperation:operation];

    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

        if (completionHandler) {
            completionHandler(responseObject, nil);
        }

    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {

        if (completionHandler) {
            completionHandler(nil, error);
        }

    }];

    [operation start];
}

And now I am looking to clear the NSURLCredentials in a logout method like so:

-(void)logout
{
   //Clear NSURLCredentialPersistenceForSession
}

How would I go about doing this? Should I reset the NSURLCredentials or is there away to clear them ?

UPDATE

I found this solution:

NSURLCredentialStorage *credentialStorage = [NSURLCredentialStorage sharedCredentialStorage];
    NSDictionary *credentialsDicationary = [credentialStorage allCredentials];


    for (NSURLProtectionSpace *space in [credentialsDicationary allKeys]) {

        NSDictionary *spaceDictionary = [credentialsDicationary objectForKey:space];

        for (id userName in [spaceDictionary allKeys]) {

            NSURLCredential *credential = [spaceDictionary objectForKey:userName];

            [credentialStorage removeCredential:credential forProtectionSpace:space];

        }

    }

From here: Using NSURLCredentialPersistenceForSession while request and then clearing the credentials on logout still persist the cerdentials

Is this the best way? I only have 1 credential stored. Also this code gives me a warning on this line:

NSURLCredential *credential = [spaceDictionary objectForKey:userName];

and here is the warning...how do I remove this warning?

/Users/jsuske/Documents/SSiPad(Device Only)ios7/SchedulingiPadApplication/ViewControllers/LHLoginController.m:496:73: Local declaration of 'userName' hides instance variable

UPDATE

Okay, so I have 3 methods:UserLogin, Login and LogoutButtonPressed

UserLogin: I am using AFNetworking to connect to a Windows Authenticated URL using NSURLCredential as shown above:

-(void)UserLogin:(NSString *)user andPassWordExists:(NSString *)password completionHandler:(void (^)(NSArray *resultsObject, NSError *error))completionHandler
{

   NSURL *url = [NSURL URLWithString:kIP];
   NSURLRequest *request = [NSURLRequest requestWithURL:url];

    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]
                                         initWithRequest:request];

    NSURLCredential *credential = [NSURLCredential
                                   credentialWithUser:user
                                   password:password
                                   persistence:NSURLCredentialPersistenceForSession];

    [operation setCredential:credential];


    [[NSOperationQueue mainQueue] addOperation:operation];

    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

        if (completionHandler) {
            completionHandler(responseObject, nil);
        }

    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {

        if (completionHandler) {
            completionHandler(nil, error);
        }

    }];

    [operation start];

}

This method is being called by the Login method:

- (void)Login
{
    NSString *rawString = [self.idTextField text];
    NSCharacterSet *whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet];
    [self.idTextField setText:[rawString stringByTrimmingCharactersInSet:whitespace]];


    [userName UserLogin:self.idTextField.text andPassWordExists:self.passwordTextField.text completionHandler:^(id responseObject, NSError *error) {
        if (responseObject) {

                [self.idTextField removeFromSuperview];
                [self.passwordTextField removeFromSuperview];
                [self.loginButton removeFromSuperview];
                self.idTextField = nil;
                self.passwordTextField = nil;
                //self.loginButton = nil;


                [self CreateMenu];



                [indicatorView stopAnimating];
                [indicatorView removeFromSuperview];
                indicatorView = nil;
                [loadingView removeFromSuperview];
                loadingView = nil;
        }else{


            [self CustomAlert:@"Sorry Login Failed, User and/or Passsword Incorrect"];

            [indicatorView stopAnimating];
            [indicatorView removeFromSuperview];
            indicatorView = nil;
            [loadingView removeFromSuperview];
            loadingView = nil;

        }
    }];

}

And I am trying to clear my session with the LogoutButtonPressed:

- (void)LogoutButtonPressed
{

    //@TODO: Fix Logout

    NSDictionary *credentialsDict = [[NSURLCredentialStorage sharedCredentialStorage] allCredentials];

    if ([credentialsDict count] > 0) {
        NSEnumerator *protectionSpaceEnumerator = [credentialsDict keyEnumerator];
        id urlProtectionSpace;

        while (urlProtectionSpace = [protectionSpaceEnumerator nextObject]) {
            NSEnumerator *userNameEnumerator = [[credentialsDict objectForKey:urlProtectionSpace] keyEnumerator];
            id userNameCred;

            while (userNameCred = [userNameEnumerator nextObject]) {
                NSURLCredential *cred = [[credentialsDict objectForKey:urlProtectionSpace] objectForKey:userNameCred];
                NSLog(@"cred to be removed: %@", cred);
                [[NSURLCredentialStorage sharedCredentialStorage] removeCredential:cred forProtectionSpace:urlProtectionSpace];
            }
        }
    }
}

I got this code from this example: http://www.springenwerk.com/2008/11/i-am-currently-building-iphone.html

Now my problem I am having is that when I trigger the logout button and then goto trigger the login method WITH NO CREDENTIALS I can still login, If I logout then wait 2 - 3 minutes and login with NO CREDENTIALS I can't login. Why is it behaving this way, its almost like the creds are still saved. Please help.

UPDATE

I have tried to clear the cache, cookies and creds inside my LogoutButtonPressed:

NSURLCache *sharedCache = [NSURLCache sharedURLCache];
[sharedCache removeAllCachedResponses];

NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray *cookies = [cookieStorage cookies];
id cookie;
for (cookie in cookies) {
    [cookieStorage deleteCookie:cookie];
}

NSDictionary *credentialsDict = [[NSURLCredentialStorage sharedCredentialStorage] allCredentials];
if ([credentialsDict count] > 0) {
    NSEnumerator *protectionSpaceEnumerator = [credentialsDict keyEnumerator];
    id urlProtectionSpace;
    while (urlProtectionSpace = [protectionSpaceEnumerator nextObject]) {
        NSEnumerator *userNameEnumerator = [[credentialsDict objectForKey:urlProtectionSpace] keyEnumerator];
        id userNameCreds;
        while (userNameCreds = [userNameEnumerator nextObject]) {
            NSURLCredential *cred = [[credentialsDict objectForKey:urlProtectionSpace] objectForKey:userNameCreds];
            [[NSURLCredentialStorage sharedCredentialStorage] removeCredential:cred forProtectionSpace:urlProtectionSpace];
        }
    }
}

and it still did not work.

Corbie answered 9/4, 2015 at 19:21 Comment(0)
C
5

This issue can be fixed easily by adding a random number to the end of the URL:

-(void)UserLogin:(NSString *)user andPassWordExists:(NSString *)password completionHandler:(void (^)(NSArray *resultsObject, NSError *error))completionHandler
{
   NSInteger randomNumber = arc4random() % 999;

   NSString *requestURL = [NSString stringWithFormat:@"%@?cache=%ld",kIP,(long)randomNumber];

   NSURL *url = [NSURL URLWithString:requestURL];

   NSURLRequest *request = [NSURLRequest requestWithURL:url];
     AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]
                                         initWithRequest:request];

   NSURLCredential *credential = [NSURLCredential
                                   credentialWithUser:user
                                   password:password
                                   persistence:NSURLCredentialPersistenceForSession];


    [operation setCredential:credential];
    operation.responseSerializer = [AFJSONResponseSerializer serializer];
    [[NSOperationQueue mainQueue] addOperation:operation];


    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

        if (completionHandler) {
            completionHandler(responseObject, nil);
        }

    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {

        if (completionHandler) {
            completionHandler(nil, error);
        }

    }];

    [operation start];

}

And make sure you have a random number at the end of all URLs you are calling.

Corbie answered 15/4, 2015 at 14:42 Comment(1)
What will a random number to do. Just curious to know.Conidiophore
P
1

LogoutButtonPressed is removing credentials from NSURLCredentialStorage while iterating over the same credentials - NSEnumerator doesn't support that. Are you seeing the "cred to be removed" message in the log?

You could try instead the _resetCredentials method from https://developer.apple.com/library/ios/samplecode/AdvancedURLConnections/Listings/CredentialsController_m.html.

Regardless of whether that makes a difference, it would be interesting to examine the output, from both before and after the resetCredentials call, of _dumpCredentials - or better yet do the dump in your login method, and see if there's a change immediately after the reset and then 2-3 minutes later.

Is self.passwordTextField.text getting cleared out? In the no credentials case where it logs in, does NSURLCredential credentialWithUser: give you nil?

Plasticize answered 12/4, 2015 at 1:22 Comment(6)
I do see the NSLog(@"cred to be removed: %@", cred); message, I have tried dumping the creds in my login method and both login, UserLogin and logoutbuttonpressedCorbie
Cool. Want to tell us what the dump reveals?Plasticize
same results...when I logout and try to login right away with wrong creds, I am to able to login, if I wait 2-3 mintues I am not able to login in.Corbie
Sure. The important question is did the dump show the credentials still in the system during that 2-3 min window, or not? Does the dump show the credentials gone after logout? Also see my questions in my last paragraph above.Plasticize
Okay, so I have logout method with 'clears' the creds. I put that same code in the login method so it running that code twice. I can see the first NSLog on logout, but not the second NSLog on login. I looked at my break points and see there are no creds on login and self.passwordTextField.text is getting cleared out.Corbie
Hmm... at this point perhaps it's time to check the server logs. Perhaps your server guys have a built-in timeout and aren't really logging you out? (Are you sending a session ID with the login?)Plasticize

© 2022 - 2024 — McMap. All rights reserved.