I am developing an app for SharePoint online and wanted to use the SharePoint Rest interfaces in my ios app. Can Some one please tell me the steps to use SharePoint Rest interfaces in iOS
I got it, below are the steps to be followed:
Include RestKit in your ios app.
Create a UIView in your home screen and load the login page.
load http: //server name/Pages/default.aspx in the UIWebView
In webViewDidFinished method find out the Fed Auth token and append it with the request URL
- (void)webViewDidFinishLoad:(UIWebView *)webView {
//Retrive HTTPOnly Cookie
NSHTTPCookieStorage *storage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray *cookiesArray = [storage cookies];
//Search for Fed Auth cookie
for (NSHTTPCookie *cookie in cookiesArray) {
if ([[cookie name] isEqualToString:#"FedAuth"]) {
/*** DO WHATEVER YOU WANT WITH THE COOKIE ***/
NSLog(#"Found FedAuth");
NSURL *url=[NSURL URLWithString:#"http://my server/_vti_bin/listdata.svc"];
RKClient *client = [RKClient clientWithBaseURL:url];
client.requestQueue.requestTimeout = 10;
client.cachePolicy = RKRequestCachePolicyNone;
client.authenticationType = RKRequestAuthenticationTypeHTTPBasic;
client.username = #"username";
client.password = #"Password";
NSString *cookieVale=[cookie value];
NSString *getResourcePath=[#"?" stringByAppendingFormat:#"%#",cookieVale];
[client get:getResourcePath delegate:self];
break;
}
}
}
And here you can find the response.
- (void)request:(RKRequest *)request didLoadResponse:(RKResponse *)response {
id xmlParser = [[RKParserRegistry sharedRegistry] parserForMIMEType:RKMIMETypeXML];
NSError *error = nil;
id parsedResponse = [xmlParser objectFromString:[response bodyAsString] error:&error];
RKLogInfo(#"Parsed response : %#, error:%#",parsedResponse,error);
if ([response isSuccessful]) {
NSLog(#"%d",[response isCreated]);
// Response status was 200..299
if ([response isCreated] && [response isJSON]) {
// Looks like we have a 201 response of type application/json
RKLogInfo(#"The JSON is %#", [response bodyAsJSON]);
}
} else if ([response isError]) {
// Response status was either 400..499 or 500..599
RKLogInfo(#"Ouch! We have an HTTP error. Status Code description: %#", [response localizedStatusCodeString]);
}
}
The self accepted answer lost me lots of hours of trials and errors. It omits some key aspects like the fact that you also need to grab the rtFa cookie. And what's up with client.username = #"username" and client.password = #"Password" provided in the users code. What is that? Note that the client does not know the username or password at any moment...
AAAnyway, below is a great article which will guide you in the right direction:
http://www.codeproject.com/Articles/571996/Development-of-iPhone-client-application-for-Share
And this describes how to get the cookies without using a UIWebView
http://allthatjs.com/2012/03/28/remote-authentication-in-sharepoint-online/
Send the FedAuth cookie with all your subsequent Requests.
Once authenticated, you can call the REST API, documentation here:
http://msdn.microsoft.com/en-us/library/fp142385(v=office.15).aspx#bk_determining
When the user finish the sign in process towards a Office365 Sharepoint instance, the web view will be redirected in several steps. As one of the final steps before loading the actual Sharepoint web site, the web view will be asked to load "about:blank".
Detect when you web view starts loading "about:blank" and you know when the user finished the sign in process and can close the web view. Example code below.
// Load page in web view
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSLog(#"WebView should start loading %#", request.URL.absoluteString);
// Detect that the user finished the sign in process
if ([request.URL.absoluteString isEqualToString:#"about:blank"]) {
// Do your stuff here
return NO;
}
return YES;
}
The Sharepoint instance will also set the FedAuth cookie if the authentication was successful. The cookie must be included in future requests to the server.
You do not have to append the cookie manually, this will be taken care of by the URL loading system as long as the cookies has been accepted and stored in the NSHTTPCookieStorage and you are sending the request to the same server.
From Apple documentation
The URL loading system automatically sends any stored cookies
appropriate for an NSURLRequest. unless the request specifies not to
send cookies. Likewise, cookies returned in an NSURLResponse are
accepted in accordance with the current cookie acceptance policy.
Related
I'd like to receive a cookie containing login status through WKwebview.
what I finally want is receiving that cookie data, parsing them,and then changing the view for the user logged in.
What I've tired :
webview.evaluateJavascript("document.cookie.search('LoginSession=Y')") { (data,error) -> .....
}
result : if the data is 'data >= 1', login status(a variable in IOS app) = true, but under 0(data < 0),login status will be false.
and it works like a charm seemingly for my app.
However, This way looks very a physical and simple way, so I think, it could be not secure for some users, and It might have no guarantee for working perfectly for all environments with IOS.
Q1 : Is it not dangerous way?
Q2 : I've heard that IOS stores the cookies in Memory unlike other platforms, and we could manage to load the cookie data from Memory through some codes. Are there any recommended libraries for developers to handle cookies from WKWEB?
I tried this. Javascript returns a single string with all cookies in form "key=value;"
I don't know how stable it is. Hope it helps.
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation{
[webView evaluateJavaScript:#"document.cookie;" completionHandler:^(NSString *result, NSError *error)
{
NSLog(#"Error getting cookies: %#",error);
[self updateCookies:result];
}];
}
Courtesy : Siyu Song's Answer
You can have access to an NSHTTPURLResponse object in - webView:decidePolicyForNavigationResponse:decisionHandler: method defined on WKNavigationDelegate. You can later extract the cookies manually from the HTTP header:
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {
NSArray *cookies = [NSHTTPCookie cookiesWithResponseHeaderFields:[response allHeaderFields] forURL:[NSURL URLWithString:#""]];
for (NSHTTPCookie *cookie in newCookies) {
// Do something with the cookie
}
decisionHandler(WKNavigationResponsePolicyAllow);
}
Please post your solution if you have a better one.
I am trying to implement Nest Thermostat in My Application i Can success fully create pin authentication code but
--->i struck in while storing that pin authentication code because after checking if condition if ([[url host] isEqualToString:[redirectURL host]]) then,
--->always condition fails if condition success then only i can store it and get access token by using it (as per library)
I did as per Nest Sample code and Library and online solutions no use I am looking for Picking hands
Plz Ref-fear my code
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
NSURL *url = [request URL];
NSURL *redirectURL = [[NSURL alloc] initWithString:RedirectURL];
if ([[url host] isEqualToString:[redirectURL host]])
{
NSString *urlResources = [url resourceSpecifier];
urlResources = [urlResources stringByReplacingOccurrencesOfString:QUESTION_MARK withString:EMPTY_STRING];
urlResources = [urlResources stringByReplacingOccurrencesOfString:HASHTAG withString:EMPTY_STRING];
NSArray *urlResourcesArray = [urlResources componentsSeparatedByString:SLASH];
NSString *urlParamaters = [urlResourcesArray objectAtIndex:([urlResourcesArray count]-1)];
NSArray *urlParamatersArray = [urlParamaters componentsSeparatedByString:AMPERSAND];
NSString *keyValue = [urlParamatersArray lastObject];
NSArray *keyValueArray = [keyValue componentsSeparatedByString:EQUALS];
if([[keyValueArray objectAtIndex:(0)] isEqualToString:#"code"]) {
[self.delegate foundAuthorizationCode:[keyValueArray objectAtIndex:1]];
} else {
NSLog(#"Error retrieving the authorization code.");
}
return NO;
}
return YES;
}
The webview which is showing pin that is only screen i can see. after that i struck it .Desperately needed help
Use web base authentication and Fill the redirect url at the time of registering the client , this redirect url should not be empty on the client page,then once you enter the device login credentials into your app then it automatically redirect and gives the authentication token then with that authentication token access token will be provided , by using that access token you can get the device details
I am using NSURLAuthenticationChallenge to log in to a webserver through my app. All the server requires is a username and a password. Here is what's happening:
(1) Ping server with POST message containing a User-Agent string in the HTML header
(2) Server responds with an authentication challenge which is detected by the didReceiveAuthenticationChallenge delegate method
(3) Respond by sending a challenge response using username and password:
NSURLCredential *cred = [[NSURLCredential alloc] initWithUser:unameTextField.text
password:pswdTextField.text
persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:cred forAuthenticationChallenge:challenge];
(4) If username/password are correct, delegate method connectionDidFinishLoading gets called, detecting that the challenge response was accepted by the server. User is now logged in and can send/receive messages from the server. (If username/password are incorrect, delegate method didFailWithError gets called and user is shown an alert.)
Here's where it's going wrong: the very first time I open my Xcode project and run the app and attempt to login with the correct username/password, there is a time lag of 10-15 seconds between steps 3 and 4. And then even after connectionDidFinishLoading is called, when I send messages to the server requesting files it responds by sending me the HTML login page which is the default behavior for unauthenticated requests...so it seems as though I'm not logged in after all.
If I stop and then run the app again there is no lag and everything works fine.
EDIT: I solved the above problem by clearing the URLCache, all cookies and all credentials before each login attempt. Code for these 3 methods is below:
- (void)clearCookiesForURL
{
NSURL *loginUrl = [NSURL URLWithString:#"https://www.MYURL.com"];
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
NSArray *cookies = [cookieStorage cookiesForURL:loginUrl];
for (NSHTTPCookie *cookie in cookies)
{
[cookieStorage deleteCookie:cookie];
}
}
- (void)eraseCredentials
{
NSString *urlString = #"www.MYURL.com";
NSURLCredentialStorage *credentialsStorage = [NSURLCredentialStorage sharedCredentialStorage];
NSDictionary *allCredentials = [credentialsStorage allCredentials];
if ([allCredentials count] > 0)
{
for (NSURLProtectionSpace *protectionSpace in allCredentials)
{
if ([[protectionSpace host] isEqualToString:urlString])
{
NSDictionary *credentials = [credentialsStorage credentialsForProtectionSpace:protectionSpace];
for (NSString *credentialKey in credentials)
{
[credentialsStorage removeCredential:[credentials objectForKey:credentialKey] forProtectionSpace:protectionSpace];
}
}
}
}
}
- (void)eraseURLCache
{
NSURL *loginUrl = [NSURL URLWithString:#"https://www.MYURL.com"];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:loginUrl];
[[NSURLCache sharedURLCache] removeCachedResponseForRequest:urlRequest];
[[NSURLCache sharedURLCache] setMemoryCapacity:0];
[[NSURLCache sharedURLCache] setDiskCapacity:0];
}
Another problem: if I wait for a long time between sending message requests to the server while the app is running, the server thinks I've logged out and exhibits the same behavior described above.
EDIT: this 2nd problem remains unsolved. Additional information - it appears that the magic time lag number is 10 seconds. In other words, if I wait more than 10 seconds after the server has authenticated me to request a file from the server, it doesn't recognize my request and sends me the web login page instead, just as it would do for an unauthenticated request.
Any idea what's going on? And no, I can't simply load the webserver login page inside my app, because that doesn't meet the requirements for this project.
I use NSURLConnection to call a webservice and there is a client certificate present in my keychain which I set as the credential in - (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
After I removed this certificate and adding a new one to keychain, the NSURLConnection still maintains the credential that I give already and gives me back with 417 status error code, which was 200, before I remove the old certificate.
Is there a way to make the NSURLConnection ask for credential, forcefully.? or how can close the existing SSL connection or the authentication challenge's credentials.
NSURLConnection is fickle beast, and I've been having a similar problem for the past couple of days. But I've found a solution to my problem and a couple of suggestions to what could possibly be the reason for an issue like the one your having.
TLS
First of there is a possibility that what is happening to you is the TLS layer caching the credentials. That is due to it being computationally expensive to establish the TLS connection [1].
Possible solutions to this are to change the DNS name you are using, by for example adding a dot (.) to the end of the string since the DNS protocol accepts a string ending in dots as fully qualified DNS name. I've also seen people adding a hashtag (#) to all URL requests and thus tricking the system to never look for a stored credential but just initiate the didRecieveAuthenticationChallenge call instead [2].
Cookies
Another possibility is that the server is setting a cookie that you would need to clear. You can do that by doing the following:
-(void)clearCookies:(NSString *)urlString{
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedCookieStorage];
NSURL *url = [[NSURL alloc] initWithString urlString];
NSArray *cookies = [cookieStorage cookiesForURL:tempURL];
for(NSHTTPCookie *cookie in cookies){
//iterate over all cookies and delete them
[cookieStorage deleteCookie:cookie];
}
}
NSURLCredentialStorage
Now it could be that the credentials are still being stored in the sharedCredentialStorage and thus should be erased by doing the following:
NSURLCredentialStorage *store = [NSURLCredentialStorage sharedCredentialStorage];
if(store !=nil){
for(NSURLProtectionSpace *protectionSpace in [store allCredentials]){
NSDictionary *map = [[NSURLCredentialStorage sharedCredentialStorage]
credentialsForProtectionSpace:protectionSpace];
if(map!=nil){
for(NSString *user in map){
NSURLCredential *cred = [map objectForKey:user];
[store removeCredential:cred forProtectionSpace:protectionSpace];
}
}
}
}
I hope that these will help.
I'm currently building an iOS application and want to include Flattr-Support over the Flattr-API v2.
I've already created my application at https://flattr.com/apps/ and got the key and secret.
The problem is that I have to provide a callback-URL in the application-settings at flattr even if I select "client" as application type. In addition only http://... callback-URLs seem to be allowed in the input field so I can't set a callback URL to open my application (something like myApp://...)
How do I implement the Flattr oAuth process for client applications?
Are there any detailed instructions how to implement the flattr-authentication with a non-web-based / iOS application?
I planned to use the JDG OAuthConsumer library but this doesn't seem to work - any other iOS librarys I could use?
A short description of my implementation using the Flattr API v2 to flattr a thing from my iOS application:
I'm currently using the "Google Toolbox for Mac - OAuth 2 Controllers":
http://code.google.com/p/gtm-oauth2/
Create a Token to be authenticated:
- (GTMOAuth2Authentication *)flattrAuth {
NSURL *tokenURL = [NSURL URLWithString:#"https://flattr.com/oauth/token"];
// We'll make up an arbitrary redirectURI. The controller will watch for
// the server to redirect the web view to this URI, but this URI will not be
// loaded, so it need not be for any actual web page.
NSString *redirectURI = #"http://localhost/"; //for me localhost with / didn't work
GTMOAuth2Authentication *auth;
auth = [GTMOAuth2Authentication authenticationWithServiceProvider:#"MyApplication"
tokenURL:tokenURL
redirectURI:redirectURI
clientID:clientKey
clientSecret:clientSecret];
return auth;
}
Create a ViewController to authenticate the token:
- (GTMOAuth2ViewControllerTouch*)getSignInViewController{
GTMOAuth2Authentication *auth = [self flattrAuth];
// Specify the appropriate scope string, if any, according to the service's API documentation
auth.scope = #"flattr";
NSURL *authURL = [NSURL URLWithString:#"https://flattr.com/oauth/authorize"];
GTMOAuth2ViewControllerTouch *viewController;
viewController = [[[GTMOAuth2ViewControllerTouch alloc] initWithAuthentication:auth
authorizationURL:authURL
keychainItemName:keychainItemName
delegate:self
finishedSelector:#selector(viewController:finishedWithAuth:error:)] autorelease];
return viewController;
}
and the delegate method:
- (void)viewController:(GTMOAuth2ViewControllerTouch *)viewController
finishedWithAuth:(GTMOAuth2Authentication *)auth
error:(NSError *)error {
if (error != nil) {
DLog(#"Flattr sign-in failed with error: %#", [error localizedDescription]);
} else {
DLog(#"Flattr Signin success");
authToken = [auth retain];
}
}
You can display the Viewcontroller in your application - it displays the flattr-login to the user so he can authenticate the application.
You can flattr a thing with the authentication token this way:
NSString* flattrURL = #"https://api.flattr.com/rest/v2/things/%qi/flattr";
NSURL* u = [NSURL URLWithString:[NSString stringWithFormat:flattrURL, item.flattrThingID]];
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:u];
[authToken authorizeRequest:request completionHandler:^(NSError *error){
if (error == nil) {
// the request has been authorized
NSURLConnection* connection = [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
if(!connection){
//TODO: handle error
} else {
[connection start];
}
} else {
//TODO: handle error
}
}];
Now implement the NSURLConnectection delegate methods and parse the JSON responses.
The GTMOAuth2 library allows you to save the authenticated token to the keychain. Look at their introduction at http://code.google.com/p/gtm-oauth2/wiki/Introduction#Retrieving_Authorization_from_the_Keychain for instructions.
When you wan't to authenticate a desktop/mobile app you would wan't to use the oauth2 implicit grant flow. As you register your flattr application use a application specific URI that will callback to your application, ex. iphone-application://oauth-callback.
When you authenticate the application with us you use the response_type token instead of code. This will create a token at once and redirect you back to your application.
Ex. request URL: https://flattr.com/oauth/authorize?client_id=2134&redirect_uri=iphone-application://oauth-callback&response_type=token
If the resource owner will authorize your application we will send a HTTP 302 and redirect you back to your redirect uri.
Ex. response 302 Location: iphone-application://oauth-callback#access_token=e5oNJ4917WAaJaO4zvoVV2dt3GYClPzp&token_type=bearer
Currently we don't have any detailed documentation explaining how to do the implicit grant but we are working on the documentation. Meanwhile i'm all ears.
https://github.com/nxtbgthng/OAuth2Client is a iOS oauth2 library but I don't know if it's any good.
This one looks good: https://github.com/neonichu/FlattrKit