After login WKWebView Session Logout in iOS - uiwebview

In my app, I want to do login using WKWebView and then all further request to server is done.
I'm able to perform successful login using WKWebView. On it's success I get session information. I had implemented it previously using UIWebView and it was working properly. All my further web service call were working fine in UIWebView.
Now when I implemented login with WKWebView it is successfully login but when i hit different link (URL) it gives me logout response every time and I'm trying to call service using Cookies and , it's not giving me proper response as session information are not being passed.
Is there any way, I can store those session information of WKWebView
Any help will be appreciated. Please help!
Here is the code where i m set cookies : -
*{
// Set iPad cookie for our requests
NSString* dotDomain = [NSString stringWithFormat:#".%#", CookieDomain];
NSDictionary* newCookieDict = [NSMutableDictionary
dictionaryWithObjectsAndKeys:
dotDomain, NSHTTPCookieDomain,
#"iPad", NSHTTPCookieName,
#"/", NSHTTPCookiePath,
#"1", NSHTTPCookieValue,
#"2040-1-1 00:00:00 -0700", NSHTTPCookieExpires,
nil];
NSHTTPCookie* newCookie = [NSHTTPCookie cookieWithProperties:newCookieDict];
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:newCookie];
}
// Don't block cookies, so dosespot will work
NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
[cookieStorage setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];*
Here is my Request HTTP Header and Response HTTP Header :-
*Request HTTP Header : {
"Accept-Encoding" = gzip;
Cookie = "cookie_test=1; cookie_test=1; CAKEPHP=jkn36knqoul2f14rebb8k5h882; iPad=1";
"User-Agent" = "iPad App";
}*
**Response HTTP Header : {
Connection = "Keep-Alive";
"Content-Encoding" = gzip;
"Content-Length" = 5668;
"Content-Type" = "text/html";
Date = "Tue, 10 May 2016 13:58:14 GMT";
"Keep-Alive" = "timeout=5, max=99";
Server = "Apache/2.2.22 (Ubuntu)";
Vary = "Accept-Encoding";
"X-Powered-By" = "PHP/5.3.10-1ubuntu3.15";
}**

Related

Blazor application is getting Forbidden (403) when calling an external API (which works fine in PostMan)

Visual Studio 2019, .NET 3.0 preview, Created a blazor application. Trying to get weather data from https://api.weather.gov/gridpoints/ALY/59,14/forecast.
I am using HttpClient in C#. This is getting forbidden (403) response
Tried to add CORS policty
private async Task<IWeatherDotGovForecast> RetrieveForecast()
{
string url = #"https://api.weather.gov/gridpoints/ALY/59,14/forecast";
var response = await _httpClient.GetAsync(url);
if (response != null)
{
var jsonString = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<WeatherDotGovForecast>(jsonString);
}
//return await _httpClient.GetJsonAsync<WeatherDotGovForecast>
// ("https://api.weather.gov/gridpoints/ALY/59,14/forecast");
return null;
}
I expected JSON data from https://api.weather.gov/gridpoints/ALY/59,14/forecast
Instead, I am getting Forbidden (403) status code
Your problem is not related to Blazor but weather.gov requires a User-Agent header in any HTTP request.
Applications accessing resources on weather.gov now need to provide a User-Agent header in any HTTP request. Requests without a user agent are automatically blocked. We have implemented this usage policy due to a small number of clients utilizing resources far in excess of what most would consider reasonable.
Use something like this:
var _httpClient = new HttpClient();
string url = #"https://api.weather.gov/gridpoints/ALY/59,14/forecast";
_httpClient.DefaultRequestHeaders.Add("User-Agent", "posterlagerkarte");
var response = await _httpClient.GetAsync(url);

HttpWebRequest with client certificate fails

I am using Visual Studio Mac (latest version) and need to fetch data from an IIs server (vaersion 10) with a GET request and by passing a client certificate.
Unfortunately the IIs answers with an RST packet and shows the error:
The I/O operation has been aborted becourse of either a thread exit or an application request.
I know apple uses ATS (I am using iOS 10.3.3).
I guess this has something to do with the client certificate and IIS not accepting it.
Can someone point me to a differnt mono api where I can append the client cert to a GET request?
My code so far is as follows (with request.GetResponse() waiting until timeout...):
X509Certificate2Collection certificates = new X509Certificate2Collection (certificate);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(this.uriString);
request.ClientCertificates = certificates;
request.Method = "GET";
request.ContentType = "application/json";
request.Accept = "application/json";
request.UserAgent = UserAgentString;
request.KeepAlive = false;
request.ProtocolVersion = HttpVersion.Version11;
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse ())
{
this.webResponse = response;
stream = response.GetResponseStream ();
}

authenticate to SharePoint through OKTA from back-end service

I have a need to programmatically connect to a customer's SharePoint server that uses OKTA for authentication. I saw this post which looked promising, but cannot seem to get a valid session cookie back from OKTA.
I can successfully call the /api/v1/authn endpoint and get back a sessionToken, but when I turn around and call /api/v1/sessions?additionalFields=cookieToken with that session token, I always received a 403 - Forbidden, with the following json:
{
"errorCode": "E0000005",
"errorSummary": "Invalid Session",
"errorLink": "E0000005",
"errorId": "oaew0udr2ElRfCnZvBFt075SA",
"errorCauses": []
}
Assuming I can get this resolved, I'm not sure of the URL I should call with the cookieToken. Is the url an OKTA endpoint that will redirect to SharePoint or is it an SharePoint endpoint that will setup the session with the cookie?
Update:
I am able to call this okta endpoint -> /api/v1/sessions?additionalFields=cookieToken with my user credentials as json
{
"username": "user#email.com",
"password": "P#ssw0rd"
}
And am able to retrieve a one-time cookie token that can be used with this link to start a SAML session in a browser:
https://[mydomain].okta.com/login/sessionCookieRedirect?redirectUrl=[sharepoint site url]&token=[cookie token]
That works in a browser, the user is automatically authenticated and ends up in SharePoint. However, it seems that this session "setup" is at least partly achieved through javascript as executing the same link in a programmatic HTTP client (such as Apache HTTP Client) does not work. The http client is sent through a couple of redirects and ends up in the SharePoint site, but the user is not authenticated. The response is 403 - Forbidden with the following headers:
403 - FORBIDDEN
Content-Type -> text/plain; charset=utf-8
Server -> Microsoft-IIS/8.5
X-SharePointHealthScore -> 0
SPRequestGuid -> 0ecd7b9d-c346-9081-cac4-43e41f3b159a
request-id -> 0ecd7b9d-c346-9081-cac4-43e41f3b159a
X-Forms_Based_Auth_Required -> https://[sharepoint site]/_login/autosignin.aspx?ReturnUrl=/_layouts/15/error.aspx
X-Forms_Based_Auth_Return_Url -> https://[sharepoint site]/_layouts/15/error.aspx
X-MSDAVEXT_Error -> 917656; Access denied. Before opening files in this location, you must first browse to the web site and select the option to login automatically.
X-Powered-By -> ASP.NET
MicrosoftSharePointTeamServices -> 15.0.0.4709
X-Content-Type-Options -> nosniff
X-MS-InvokeApp -> 1; RequireReadOnly
Date -> Fri, 13 May 2016 15:02:38 GMT
Content-Length -> 13
I'm starting to wonder if this is a lost cause, that OKTA or SharePoint doesn't support programmatic authentication via SAML.
It's possible.
Here is what I did.
1) Get your sessionToken from Okta. You'll need an okta authorization token for that.
2) Do a HttpGet(sharepointEmbeddedLink + "?onetimetoken=" + sessionToken)
Also add this header: new BasicHeader(AUTHORIZATION, String.format("SSWS %s", OKTA_AUTHORIZATION_TOKEN);
3) Next you'll have to parse the html response and get the SAML Arguments: WRESULT, WCTX, WA
4) Next do this - take those 3 and create a string in this format "application/x-www-form-urlencoded". It will be something like this "wa=wsign1.0&wctx=somevalue&wresult=somevalue".
byte[] out = theStringAbove.getBytes;
int length = out.length;
URL url = new URL("https://login.microsoftonline.com/login.srf");
URLConnection con = url.openConnection();
HttpURLConnection http = (HttpURLConnection) con;
http.setRequestMethod("POST"); // PUT is another valid option
http.setDoOutput(true);
http.setInstanceFollowRedirects(true);
http.setFixedLengthStreamingMode(length);
http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
http.setRequestProperty("User-agent", "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.215 Safari/535.1");
http.connect();
http.getOutputStream().write(out);
5) You'll have the saml Token in the response. You'll have to parse an html file again.
6) You'll get the sharepoint siteUrl in step3 or 4 and do this next :)
HttpPost httpPost = new HttpPost(siteUrl + "_forms/default.aspx?wa=wsignin1.0");
byte[] utf8TokenStringBytes = ("t=" + samlToken).getBytes(StandardCharsets.UTF_8);
HttpEntity entity = new ByteArrayEntity(utf8TokenStringBytes);
httpPost.setEntity(entity);
httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
httpPost.setHeader("User-agent", "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/13.0.782.215 Safari/535.1");
HttpResponse response = httpclient.execute(httpPost, httpContext);
If everyting is ok, you'll have some cookie headers that you can use :D

Can't insert items into table after google authentication in Azure mobile service

I am testing the sample code from Azure Mobile Service site. It's a todo app for iOS. There is a button to create a table for this app in the Azure site. And the app works well.
But after I turned on authentication for google option in the site, I couldn't insert or fetch todos from Azure server. I signed in google through the app and MSClient:loginWithProvider was successful.
[self.todoService.client loginWithProvider:#"google" controller:self animated:YES completion:^(MSUser * _Nullable user, NSError * _Nullable error) {
if (error==nil) {
// obviously successful
NSLog(#"login success %#", user.userId);
}
[self dismissViewControllerAnimated:YES completion:nil];
}];
But whenever I inserted new todo, I got this error.
2016-02-03 00:15:52.311 TryMobileApp[7432:1327892] Error Domain=com.Microsoft.MicrosoftAzureMobile.ErrorDomain Code=-1201 "The server did not return the expected item." UserInfo={NSLocalizedDescription=The server did not return the expected item., com.Microsoft.MicrosoftAzureMobile.ErrorRequestKey=<NSMutableURLRequest: 0x7c258d90> { URL: http://thehome.azurewebsites.net/tables/TodoItem }, com.Microsoft.MicrosoftAzureMobile.ErrorResponseKey=<NSHTTPURLResponse: 0x7ae095e0> { URL: https://thehome.azurewebsites.net/tables/TodoItem } { status code: 200, headers {
"Cache-Control" = "no-cache";
"Content-Encoding" = gzip;
"Content-Length" = 326;
"Content-Type" = "application/json; charset=utf-8";
Date = "Tue, 02 Feb 2016 16:15:51 GMT";
Etag = "W/\"186-ChUpLnifKBz6ME0BS21A5w\"";
Expires = 0;
Pragma = "no-cache";
Server = "Microsoft-IIS/8.0";
Vary = "Accept-Encoding";
"X-Powered-By" = "Express, ASP.NET";
} }}
If I turned off the authentication option in the Azure site, it worked well again.
Any suggestion?

ServiceStack auth cookies different clients

I encouraged my company to use ServiceStack for one of the software projects. I am loving servicestack framework by all means. I came accross a problem that I couldn't figure out by myself.
In a web application i am using ServiceStack c# Jsonclient from a login page to authenticate. When i get authenticated c# client hold the ss-id cookies in it. So when i use same c# client for service calls i can access the session within my services.
But there is a autocomplete feature which calls a service by Jquery AJAX call the client there (browser) is not authenticated and browser does not hold ss-id cookie also.
My question is when i authenticate with c# client on code-behind. How can i store session cookies on browser (Is that needed?) so when i call service from javascript client i can access session in my services also.
Thanks for the response.
My question is when i authenticate with c# client on code-behind. How can i store session cookies on browser (Is that needed?)
So, your browser needs to have a session cookie to let ServiceStack know that it has been successfully authenticated. The browser knows nothing about what is happening with your C# clients. I'm not sure how you are posting your authentication data (username/password/etc) but if it is through a browser and you're handing the data off to a C# client you could do something like below. This is wihin MVC but the point is to get the session cookie out of the client and into the response to the browser.
public ActionResult Login()
{
var client = new JsonServiceClient("http://localhost");
var response = client.Post(new Auth() {UserName = "TestUser", Password = "Password"} );
var ssId = "";
foreach(Cookie c in client.CookieContainer.GetCookies(new Uri("http://localhost")))
{
if (c.Name == "ss-id")
{
ssId = c.Value;
}
}
var cookie = new HttpCookie("ss-id", ssId);
this.ControllerContext.HttpContext.Response.SetCookie(cookie);
return new EmptyResult();
}
If you are using MVC this would be a better way. However, I'm not sure your reasoning for using C# clients and how your are receiving the authentication data and your ability to get into the Response to the browser.
Setting both "ss-id" and "ss-pid" cookies works for me when authenticating the browser as well as the .NET client.
A somewhat rewritten part of my logon controller:
[HttpPost]
public ActionResult Logon(Auth auth)
{
using (var client = new ServiceStack.ServiceClient.Web.JsonServiceClient("://ServicestackUrl/"))
{
auth.provider = "credentials";
auth.RememberMe = true;
client.UserName = auth.UserName;
client.Password = auth.Password;
var authResponse = new AuthResponse();
try
{
authResponse = client.Send(auth);
}
catch (WebException ex)
{
throw ex;
}
foreach (Cookie c in client.CookieContainer.GetCookies(new Uri(client.BaseUri)))
{
if (c.Name == "ss-id" || c.Name == "ss-pid")
{
Response.SetCookie(new HttpCookie("ss-id", c.Value));
}
}
//Log the user on with forms authentication
string encryptedTicket = FormsAuthentication.Encrypt(
new FormsAuthenticationTicket(
1,
authResponse.UserName,
DateTime.Now,
DateTime.Now.AddMinutes(FormsAuthentication.Timeout.Minutes),
false,
""
)
);
Response.Cookies.Add(
new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket)
);
}
//Do a redirect or something
return Redirect(GetRedirectUrl);
}

Resources