| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490 |
- //
- // ASIAuthenticationDialog.m
- // Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
- //
- // Created by Ben Copsey on 21/08/2009.
- // Copyright 2009 All-Seeing Interactive. All rights reserved.
- //
- #import "ASIAuthenticationDialog.h"
- #import "ASIHTTPRequest.h"
- #import <QuartzCore/QuartzCore.h>
- static ASIAuthenticationDialog *sharedDialog = nil;
- BOOL isDismissing = NO;
- static NSMutableArray *requestsNeedingAuthentication = nil;
- static const NSUInteger kUsernameRow = 0;
- static const NSUInteger kUsernameSection = 0;
- static const NSUInteger kPasswordRow = 1;
- static const NSUInteger kPasswordSection = 0;
- static const NSUInteger kDomainRow = 0;
- static const NSUInteger kDomainSection = 1;
- @implementation ASIAutorotatingViewController
- - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
- {
- return YES;
- }
- @end
- @interface ASIAuthenticationDialog ()
- - (void)showTitle;
- - (void)show;
- - (NSArray *)requestsRequiringTheseCredentials;
- - (void)presentNextDialog;
- - (void)keyboardWillShow:(NSNotification *)notification;
- - (void)orientationChanged:(NSNotification *)notification;
- - (void)cancelAuthenticationFromDialog:(id)sender;
- - (void)loginWithCredentialsFromDialog:(id)sender;
- @property (strong) UITableView *tableView;
- @end
- @implementation ASIAuthenticationDialog
- #pragma mark init / dealloc
- + (void)initialize
- {
- if (self == [ASIAuthenticationDialog class]) {
- requestsNeedingAuthentication = [NSMutableArray array] ;
- }
- }
- + (void)presentAuthenticationDialogForRequest:(ASIHTTPRequest *)theRequest
- {
- // No need for a lock here, this will always be called on the main thread
- if (!sharedDialog) {
- sharedDialog = [[self alloc] init];
- [sharedDialog setRequest:theRequest];
- if ([theRequest authenticationNeeded] == ASIProxyAuthenticationNeeded) {
- [sharedDialog setType:ASIProxyAuthenticationType];
- } else {
- [sharedDialog setType:ASIStandardAuthenticationType];
- }
- [sharedDialog show];
- } else {
- [requestsNeedingAuthentication addObject:theRequest];
- }
- }
- - (id)init
- {
- if ((self = [self initWithNibName:nil bundle:nil])) {
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
-
- #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
- if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
- #endif
- if (![UIDevice currentDevice].generatesDeviceOrientationNotifications) {
- [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
- [self setDidEnableRotationNotifications:YES];
- }
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
- #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
- }
- #endif
- }
- return self;
- }
- - (void)dealloc
- {
- if ([self didEnableRotationNotifications]) {
- [[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
- }
- [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
-
-
- [presentingController.view removeFromSuperview];
-
- }
- #pragma mark keyboard notifications
- - (void)keyboardWillShow:(NSNotification *)notification
- {
- #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
- if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
- #endif
- #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_3_2
- NSValue *keyboardBoundsValue = [[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey];
- #else
- NSValue *keyboardBoundsValue = [[notification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey];
- #endif
- CGRect keyboardBounds;
- [keyboardBoundsValue getValue:&keyboardBounds];
- UIEdgeInsets e = UIEdgeInsetsMake(0, 0, keyboardBounds.size.height, 0);
- [[self tableView] setScrollIndicatorInsets:e];
- [[self tableView] setContentInset:e];
- #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
- }
- #endif
- }
- // Manually handles orientation changes on iPhone
- - (void)orientationChanged:(NSNotification *)notification
- {
- [self showTitle];
-
- UIInterfaceOrientation o = (UIInterfaceOrientation)[[UIApplication sharedApplication] statusBarOrientation];
- CGFloat angle = 0;
- switch (o) {
- case UIDeviceOrientationLandscapeLeft: angle = 90; break;
- case UIDeviceOrientationLandscapeRight: angle = -90; break;
- case UIDeviceOrientationPortraitUpsideDown: angle = 180; break;
- default: break;
- }
-
- CGRect f = [[UIScreen mainScreen] bounds];
-
- // Swap the frame height and width if necessary
- UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
- if (UIDeviceOrientationIsLandscape(deviceOrientation)) {
- CGFloat t;
- t = f.size.width;
- f.size.width = f.size.height;
- f.size.height = t;
- }
-
- CGAffineTransform previousTransform = self.view.layer.affineTransform;
- CGAffineTransform newTransform = CGAffineTransformMakeRotation((CGFloat)(angle * M_PI / 180.0));
-
- // Reset the transform so we can set the size
- self.view.layer.affineTransform = CGAffineTransformIdentity;
- self.view.frame = (CGRect){ { 0, 0 }, f.size};
-
- // Revert to the previous transform for correct animation
- self.view.layer.affineTransform = previousTransform;
-
- [UIView beginAnimations:nil context:NULL];
- [UIView setAnimationDuration:0.3];
-
- // Set the new transform
- self.view.layer.affineTransform = newTransform;
-
- // Fix the view origin
- self.view.frame = (CGRect){ { f.origin.x, f.origin.y },self.view.frame.size};
- [UIView commitAnimations];
- }
- #pragma mark utilities
- - (UIViewController *)presentingController
- {
- if (!presentingController) {
- presentingController = [[ASIAutorotatingViewController alloc] initWithNibName:nil bundle:nil];
-
- // Attach to the window, but don't interfere.
- UIWindow *window = [[[UIApplication sharedApplication] windows] objectAtIndex:0];
- [window addSubview:[presentingController view]];
- [[presentingController view] setFrame:CGRectZero];
- [[presentingController view] setUserInteractionEnabled:NO];
- }
-
- return presentingController;
- }
- - (UITextField *)textFieldInRow:(NSUInteger)row section:(NSUInteger)section
- {
- return [[[[[self tableView] cellForRowAtIndexPath:
- [NSIndexPath indexPathForRow:row inSection:section]]
- contentView] subviews] objectAtIndex:0];
- }
- - (UITextField *)usernameField
- {
- return [self textFieldInRow:kUsernameRow section:kUsernameSection];
- }
- - (UITextField *)passwordField
- {
- return [self textFieldInRow:kPasswordRow section:kPasswordSection];
- }
- - (UITextField *)domainField
- {
- return [self textFieldInRow:kDomainRow section:kDomainSection];
- }
- #pragma mark show / dismiss
- + (void)dismiss
- {
- //[[sharedDialog parentViewController] dismissModalViewControllerAnimated:YES];
- // jiangyh 2017-06-06 add
- [[sharedDialog parentViewController] dismissViewControllerAnimated:YES completion:nil];
- }
- - (void)viewDidDisappear:(BOOL)animated
- {
- sharedDialog = nil;
- [self performSelector:@selector(presentNextDialog) withObject:nil afterDelay:0];
-
- }
- - (void)dismiss
- {
- if (self == sharedDialog) {
- [[self class] dismiss];
- } else {
- [[self parentViewController] dismissViewControllerAnimated:YES completion:nil];
- }
- }
- - (void)showTitle
- {
- UINavigationBar *navigationBar = [[[self view] subviews] objectAtIndex:0];
- UINavigationItem *navItem = [[navigationBar items] objectAtIndex:0];
- UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
- if (UIInterfaceOrientationIsPortrait((UIInterfaceOrientation)deviceOrientation)) {
- // Setup the title
- if ([self type] == ASIProxyAuthenticationType) {
- [navItem setPrompt:@"Login to this secure proxy server."];
- } else {
- [navItem setPrompt:@"Login to this secure server."];
- }
- } else {
- [navItem setPrompt:nil];
- }
- [navigationBar sizeToFit];
- CGRect f = [[self view] bounds];
- f.origin.y = [navigationBar frame].size.height;
- f.size.height -= f.origin.y;
- [[self tableView] setFrame:f];
- }
- - (void)show
- {
- // Remove all subviews
- UIView *v;
- while ((v = [[[self view] subviews] lastObject])) {
- [v removeFromSuperview];
- }
-
- // Setup toolbar
- UINavigationBar *bar = [[ UINavigationBar alloc] init] ;
- [bar setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
-
- UINavigationItem *navItem = [ [UINavigationItem alloc] init] ;
- bar.items = [NSArray arrayWithObject:navItem];
-
- [[self view] addSubview:bar];
-
- [self showTitle];
-
- // Setup toolbar buttons
- if ([self type] == ASIProxyAuthenticationType) {
- [navItem setTitle:[[self request] proxyHost]];
- } else {
- [navItem setTitle:[[[self request] url] host]];
- }
-
- [navItem setLeftBarButtonItem:[ [UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelAuthenticationFromDialog:)] ];
- [navItem setRightBarButtonItem:[ [UIBarButtonItem alloc] initWithTitle:@"Login" style:UIBarButtonItemStyleDone target:self action:@selector(loginWithCredentialsFromDialog:)] ];
-
- // We show the login form in a table view, similar to Safari's authentication dialog
- [bar sizeToFit];
- CGRect f = [[self view] bounds];
- f.origin.y = [bar frame].size.height;
- f.size.height -= f.origin.y;
- UITableView *t = [[UITableView alloc]init];
- t.frame = f;
-
- [self setTableView:t ];
-
- [[self tableView] setDelegate:self];
- [[self tableView] setDataSource:self];
- [[self tableView] setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
- [[self view] addSubview:[self tableView]];
-
- // Force reload the table content, and focus the first field to show the keyboard
- [[self tableView] reloadData];
- [[[[[self tableView] cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]].contentView subviews] objectAtIndex:0] becomeFirstResponder];
-
- #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
- if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
- [self setModalPresentationStyle:UIModalPresentationFormSheet];
- }
- #endif
-
- [[self presentingController] presentViewController:self animated:YES completion:nil];
- }
- #pragma mark button callbacks
- - (void)cancelAuthenticationFromDialog:(id)sender
- {
- for (ASIHTTPRequest *theRequest in [self requestsRequiringTheseCredentials]) {
- [theRequest cancelAuthentication];
- [requestsNeedingAuthentication removeObject:theRequest];
- }
- [self dismiss];
- }
- - (NSArray *)requestsRequiringTheseCredentials
- {
- NSMutableArray *requestsRequiringTheseCredentials = [NSMutableArray array];
- NSURL *requestURL = [[self request] url];
- for (ASIHTTPRequest *otherRequest in requestsNeedingAuthentication) {
- NSURL *theURL = [otherRequest url];
- if (([otherRequest authenticationNeeded] == [[self request] authenticationNeeded]) && [[theURL host] isEqualToString:[requestURL host]] && ([theURL port] == [requestURL port] || ([requestURL port] && [[theURL port] isEqualToNumber:[requestURL port]])) && [[theURL scheme] isEqualToString:[requestURL scheme]] && ((![otherRequest authenticationRealm] && ![[self request] authenticationRealm]) || ([otherRequest authenticationRealm] && [[self request] authenticationRealm] && [[[self request] authenticationRealm] isEqualToString:[otherRequest authenticationRealm]]))) {
- [requestsRequiringTheseCredentials addObject:otherRequest];
- }
- }
- [requestsRequiringTheseCredentials addObject:[self request]];
- return requestsRequiringTheseCredentials;
- }
- - (void)presentNextDialog
- {
- if ([requestsNeedingAuthentication count]) {
- ASIHTTPRequest *nextRequest = [requestsNeedingAuthentication objectAtIndex:0];
- [requestsNeedingAuthentication removeObjectAtIndex:0];
- [[self class] presentAuthenticationDialogForRequest:nextRequest];
- }
- }
- - (void)loginWithCredentialsFromDialog:(id)sender
- {
- for (ASIHTTPRequest *theRequest in [self requestsRequiringTheseCredentials]) {
-
- NSString *username = [[self usernameField] text];
- NSString *password = [[self passwordField] text];
-
- if (username == nil) { username = @""; }
- if (password == nil) { password = @""; }
-
- if ([self type] == ASIProxyAuthenticationType) {
- [theRequest setProxyUsername:username];
- [theRequest setProxyPassword:password];
- } else {
- [theRequest setUsername:username];
- [theRequest setPassword:password];
- }
-
- // Handle NTLM domains
- NSString *scheme = ([self type] == ASIStandardAuthenticationType) ? [[self request] authenticationScheme] : [[self request] proxyAuthenticationScheme];
- if ([scheme isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeNTLM]) {
- NSString *domain = [[self domainField] text];
- if ([self type] == ASIProxyAuthenticationType) {
- [theRequest setProxyDomain:domain];
- } else {
- [theRequest setDomain:domain];
- }
- }
-
- [theRequest retryUsingSuppliedCredentials];
- [requestsNeedingAuthentication removeObject:theRequest];
- }
- [self dismiss];
- }
- #pragma mark table view data source
- - (NSInteger)numberOfSectionsInTableView:(UITableView *)aTableView
- {
- NSString *scheme = ([self type] == ASIStandardAuthenticationType) ? [[self request] authenticationScheme] : [[self request] proxyAuthenticationScheme];
- if ([scheme isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeNTLM]) {
- return 2;
- }
- return 1;
- }
- - (CGFloat)tableView:(UITableView *)aTableView heightForFooterInSection:(NSInteger)section
- {
- if (section == [self numberOfSectionsInTableView:aTableView]-1) {
- return 30;
- }
- return 0;
- }
- - (CGFloat)tableView:(UITableView *)aTableView heightForHeaderInSection:(NSInteger)section
- {
- if (section == 0) {
- #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
- if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
- return 54;
- }
- #endif
- return 30;
- }
- return 0;
- }
- - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
- {
- if (section == 0) {
- return [[self request] authenticationRealm];
- }
- return nil;
- }
- - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- #if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_3_0
- UITableViewCell *cell = [ [UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] ;
- #else
- UITableViewCell *cell = [[[UITableViewCell alloc] initWithFrame:CGRectMake(0,0,0,0) reuseIdentifier:nil] autorelease];
- #endif
-
- [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
-
- CGRect f = CGRectInset([cell bounds], 10, 10);
- UITextField *textField = [ [UITextField alloc] initWithFrame:f ];
- [textField setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
- [textField setAutocapitalizationType:UITextAutocapitalizationTypeNone];
- [textField setAutocorrectionType:UITextAutocorrectionTypeNo];
-
- NSUInteger s = [indexPath section];
- NSUInteger r = [indexPath row];
-
- if (s == kUsernameSection && r == kUsernameRow) {
- [textField setPlaceholder:@"User"];
- } else if (s == kPasswordSection && r == kPasswordRow) {
- [textField setPlaceholder:@"Password"];
- [textField setSecureTextEntry:YES];
- } else if (s == kDomainSection && r == kDomainRow) {
- [textField setPlaceholder:@"Domain"];
- }
- [cell.contentView addSubview:textField];
-
- return cell;
- }
- - (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section
- {
- if (section == 0) {
- return 2;
- } else {
- return 1;
- }
- }
- - (NSString *)tableView:(UITableView *)aTableView titleForFooterInSection:(NSInteger)section
- {
- if (section == [self numberOfSectionsInTableView:aTableView]-1) {
- // If we're using Basic authentication and the connection is not using SSL, we'll show the plain text message
- if ([[[self request] authenticationScheme] isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeBasic] && ![[[[self request] url] scheme] isEqualToString:@"https"]) {
- return @"Password will be sent in the clear.";
- // We are using Digest, NTLM, or any scheme over SSL
- } else {
- return @"Password will be sent securely.";
- }
- }
- return nil;
- }
- #pragma mark -
- @synthesize request;
- @synthesize type;
- @synthesize tableView;
- @synthesize didEnableRotationNotifications;
- @synthesize presentingController;
- @end
|