Quelqu'un a-t-il intégré une application iPhone avec un fournisseur d'identité shibboleth? Googling n'a pas marché quelque chose, alors je demande directement aux gourous. P>
Si ce n'est pas déjà fait des dons, est-ce réalisable de le faire? P>
3 Réponses :
la réponse à la fois est "oui". strong> Je suis un gars Java, alors étant posé il y a deux semaines à: p> ... était un peu décourageant. Composé que, avec l'absence de tout post de forum pour aider, m'a incité à partager mon expérience. P> Voici un aperçu suivi d'un code d'échantillon très utile. S'il vous plaît voter pour ma réponse si cela aide! Cela vaut quelques semaines de mon temps :) p> Pour une application sur l'iPhone de télécharger des ressources shibbbolisées, les informations suivantes doivent se produire: P> Voici quelques références utiles de Apple et Shibboleth: P> et j'espère que je peux inclure toute la source d'une démonstration rapide. P>
ApplicationDelegate.h
----------
#import <UIKit/UIKit.h>
#import "ConsoleViewController.h"
/*
The application delegate will hold references to the application's UIWindow and a ConsoleViewController.
The console does all of the interesting Shibboleth activities.
*/
@interface ApplicationDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
ConsoleViewController *consoleViewController;
}
@end
ApplicationDelegate.m
----------
#import "ApplicationDelegate.h"
#import "ConsoleViewController.h"
/*
The implementation for the ApplicationDelegate initializes the console view controller and assembles everything.
The console does all of the interesting Shibboleth activities.
*/
@implementation ApplicationDelegate
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Initialize the console.
consoleViewController = [[ConsoleViewController alloc] init];
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[window setBackgroundColor:[UIColor lightGrayColor]];
[window addSubview:[consoleViewController view]];
[window makeKeyAndVisible];
}
- (void)dealloc {
[window release];
[ConsoleViewController release];
[super dealloc];
}
@end
ConsoleController.h
----------
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
/*
The ConsoleViewController's interface declares references to the network data used in negotiating with Shibboleth
and a UITextView used to display the final result or errors.
*/
@interface ConsoleViewController : UIViewController {
NSMutableData *responseData;
NSString *responseString;
UITextView *console;
}
@end
ConsoleController.m
----------
#import "ApplicationDelegate.h"
#import "ConsoleViewController.h"
/*
This delegate is used when making the second HTTP request with Shibboleth. If you're just getting here, start
by reading the comments for ConsoleViewController below.
All we need to do now is receive the response from the SP and display it.
If all goes well, this should be the secured page originally requested.
*/
@interface AuthenticationRedirectDelegate : NSObject {
NSMutableData *authResponseData;
NSString *authResponseString;
UITextView *console;
}
@property (nonatomic retain) UITextView *console;
@end
/*
Refer to the comments for the interface above.
*/
@implementation AuthenticationRedirectDelegate
@synthesize console;
-(id)init {
authResponseData = [[NSMutableData alloc] retain];
return self;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[authResponseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[authResponseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[console setText:[error localizedDescription]];
}
/*
Once the data is received from Shibboleth's SP, display it.
*/
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
authResponseString = [[NSString alloc] initWithData:authResponseData encoding:NSUTF8StringEncoding];
[console setText:authResponseString];
[connection release];
}
@end
/*
The implementation of the ConsoleViewController, and AuthenticationRedirectDelegate above, contain the real logic of
this Shibboleth exercise. The ConsoleViewController performs the following:
1. Prepare the initial HTTP request to a Shibboleth protected resource.
2. Act as the delegate whilst Cocoa's URL Loading API receives the HTTP Response.
NOTE: We instruct Cocoa in advance to take care of the SP redirecting to the IdP, accepting the server certificate,
and submitting the user credentials
3. Once the HTTP Response is finished loading, parse the <form action, RelayState and SAMLResponse from the IdP's
response
4. Call a utility method to prepare a second HTTP POST Request to the <form action/SP with the IdP's parameters
NOTE: We do not need to transfer over any of Shibboleth's cookies, since Cocoa is doing this automatically
5. Use a new instance of AuthenticationRedirectDelegate to receive the POST's response, which should be the secured
page originally requested.
6. Display the final content in the UITextView known as console.
*/
@implementation ConsoleViewController
/*
A handy utility method for extracting a substring marked by two provided token strings.
Used in parsing the HTML form returned by the IdP after the first HTTP Request.
*/
+(id)substringFromString:(NSString *)source BetweenOpenToken:(NSString *)openToken AndCloseToken:(NSString *)closeToken {
NSUInteger l = [source length];
NSUInteger openTokenLen = [openToken length];
NSUInteger openTokenLoc = ([source rangeOfString:openToken]).location;
NSUInteger valueLoc = openTokenLoc + openTokenLen;
NSRange searchRange = NSMakeRange(valueLoc, l - valueLoc);
NSUInteger closeTokenLoc = ([source rangeOfString:closeToken options:NSCaseInsensitiveSearch range:searchRange]).location;
searchRange = NSMakeRange(valueLoc, closeTokenLoc - valueLoc);
NSString *result = [source substringWithRange:searchRange];
return result;
}
/*
This function takes the three properties returned by the IdP after the first HTTP request and
HTTP POSTs them to the SP as specified by the IdP in the "url" parameter.
*/
-(void)authReturnTo:(NSURL *)url WithRelay:(NSString *)relayState AndSAML:(NSString *)samlResponse {
// Here we assemble the HTTP POST body as usual.
NSString *preBody = [[NSString alloc] initWithString:@"RelayState="];
preBody = [preBody stringByAppendingString:relayState];
preBody = [preBody stringByAppendingString:@"&"];
preBody = [preBody stringByAppendingString:@"SAMLResponse="];
preBody = [preBody stringByAppendingString:samlResponse];
/* The SAMLResponse parameter contains characters (+) that the SP expects to be URL encoded.
Here we simply manually URL encode those characters. You may wish to harden this with proper
URL encoding for production use.
*/
NSString *httpBody = [preBody stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"];
NSData *httpBodyData = [httpBody dataUsingEncoding:NSUTF8StringEncoding];
NSString *httpContentLength = [NSString stringWithFormat:@"%d", [httpBodyData length]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:12.0];
[request setHTTPMethod:@"POST"];
[request setValue:httpContentLength forHTTPHeaderField:@"Content-Length"];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody:httpBodyData];
// Submit the HTTP POST using the second delegate class to receive the response
AuthenticationRedirectDelegate *delegate = [[AuthenticationRedirectDelegate alloc] init];
delegate.console=console;
[[NSURLConnection alloc] initWithRequest:request delegate:delegate];
}
/*
When this UIViewController finishes loading, automatically prepare and send a request to the Shibboleth SP Web Server
for a secured resource.
*/
- (void)viewDidLoad {
[super viewDidLoad];
console = [[UITextView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[[self view] addSubview:console];
responseData = [[NSMutableData data] retain];
// TODO: Enter your own URL for a Shibboleth secured resource.
NSURL *url = [NSURL URLWithString:@"<URL>"];
NSURLRequest *request = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:12.0];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
/* Control flows to the delegate methods below */
}
/*
Refer to Apple's docs on the URL Loading System for details.
http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Conceptual/URLLoadingSystem/URLLoadingSystem.html
*/
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[responseData setLength:0];
}
/*
Refer to Apple's docs on the URL Loading System for details.
http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Conceptual/URLLoadingSystem/URLLoadingSystem.html
*/
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
/*
This implementation in the delegate let's Cocoa trust my SP Web Server's self-signed certificate.
TODO: You will want to harden this for production use.
Refer to Apple's docs on the URL Loading System for details.
http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Conceptual/URLLoadingSystem/URLLoadingSystem.html
*/
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust] || [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPBasic];
}
/*
This implementation for the delegate does two things:
1. Respond to challenges for my server's self-signed certificate
2. Respond to the IdP's challenge for the username and password.
TODO: Enter your own username and password here.
Refer to Apple's docs on the URL Loading System for details.
http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Conceptual/URLLoadingSystem/URLLoadingSystem.html
*/
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
// TODO: Enter the correct username and password below.
/*
WARNING: Using an incorrect user name and password will result in your application being re-challenged
by the IdP. Cocoa will return to this function in a never-ending loop. This can result in the message
"NSPosixErrorDomain Too many open files". You'll need to perform additional coding to handle this.
*/
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
else if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodHTTPBasic])
[challenge.sender useCredential:[NSURLCredential credentialWithUser:@"<USERNAME>" password:@"<PASSWORD>" persistence:NSURLCredentialPersistenceNone] forAuthenticationChallenge:challenge];
else
[challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}
/*
You may wish to add more code here to log errors.
Refer to Apple's docs on the URL Loading System for details.
http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Conceptual/URLLoadingSystem/URLLoadingSystem.html
*/
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[console setText:[error localizedDescription]];
}
/*
Once Cocoa has received a (hopefully) authenticated response from the IdP, we parse out the relevant pieces and prepare to
HTTP POST them back to the SP as specified by the IdP in the <form action attribute.
Refer to Apple's docs on the URL Loading System for details.
http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Conceptual/URLLoadingSystem/URLLoadingSystem.html
*/
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[connection release];
responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
if([responseString rangeOfString:@"SAMLResponse"].length < 1)
{
[console setText:[@"Unexpected response:\n]n" stringByAppendingString:responseString]];
return;
}
NSString *relayState = [ConsoleViewController substringFromString:responseString BetweenOpenToken:@"RelayState\" value=\"" AndCloseToken:@"\"/>"];
NSString *SAMLResponse = [ConsoleViewController substringFromString:responseString BetweenOpenToken:@"SAMLResponse\" value=\"" AndCloseToken:@"\"/>"];
NSString *formAction = [ConsoleViewController substringFromString:responseString BetweenOpenToken:@"<form action=\"" AndCloseToken:@"\""];
NSURL *formActionURL = [[NSURL alloc] initWithString:formAction];
[self authReturnTo:formActionURL WithRelay:relayState AndSAML:SAMLResponse];
}
@end
Nice, mais cela ne fonctionne pas avec l'authentification basée sur la forme où avez-vous besoin d'analyser le HTML ou de le présenter à l'utilisateur pour l'interaction. Dans mon cas, l'utilisateur doit itération sur plusieurs facteurs d'authentification, donc je ne peux donc pas en sortir. Quoi qu'il en soit, je peux traduire votre échantillon en C #, ma langue de choix pour le développement de l'iPhone et l'utiliser comme base. Merci
J'ai mis en œuvre avec succès à l'aide de la solution de CE comme point de départ. La seule autre chose que j'ajouterais est que vous devez vraiment faire attention à ne conserver qu'une demande à la fois. Dans notre mise en œuvre, le processus d'authentification serait confus entre plusieurs demandes asynchrones fonctionnant simultanément. Utiliser Nsoperation pour manipuler la file d'attente semblait travailler très bien pour moi. P>
J'ai réussi à faire exactement cela, mais cela m'a fallu du temps pour comprendre chaque étape du processus et la reproduire parfaitement. Si j'ai le temps, je pourrais écrire un tutoriel détaillé, car je n'ai trouvé aucune aide pour beaucoup de problèmes que j'ai obtenus. La chose est que cela dépend également du site Web que vous souhaitez vous connecter, de sorte que vous ne suivez peut-être pas le même chemin que le mien (son processus est identique à celui décrit ici ). P>
Pour voir chaque demande tirée par mon navigateur (chrome) pour vous connecter, j'ai utilisé le panneau de réseau Outils de développeur, avec "LOG conserve". P>
Quelques astuces: P>
1 °) Vous devez obtenir "_IDP_Authn_lc_key ..." Cookie. Il y a une demande qui le définit pour vous, trouvez-la. P> Li>
2 °) Vous avez besoin du ticket de connexion (LT -...). Vous le trouverez probablement dans le corps de la page qui vous demande vos informations d'identification. P> li>
3 °) Vous avez besoin d'un ticket de service (ST -...). Encore une fois, vous le trouverez dans la page que la requête précédente est revenue. P> li>
4 °) Vous avez besoin de samlresponse. Encore une fois, vous le trouverez dans la page que la requête précédente est revenue. P> li>
5 °) Enfin, vous pouvez vous connecter en renvoyant Samlreesponse au fournisseur de services. Vous devriez prendre soin du codage, ici. J'en ai eu quelques "+" ou "=" que je devais changer de "% 2b" et "% 3D". Vous recevrez un cookie "_idp_session", qui vous permettra de vous reconnecter sans tout ce désordre. P> li> ul>
Si quelqu'un essaie de faire de même, je serais heureux d'aider! Envoyez-moi juste un message. P>
Parlez-vous d'une application Web ou d'une application native?
application native; Ou la page Web iPhone pourrait-elle authentifier une application native?