Adding cookies on loading a url on web view - xamarin.ios

I am creating an iOS app using Xamarin.
I am loading a url on a web view. This url is hosted on a secure server which needs to be authenticated.
I store cookies from login service of the app and want to set these cookies when loading the web view. But I cannot get any method to add it.
Could any one help regarding this?
Loading url is done by this line webview.LoadRequest(new NSUrlRequest(urlq));
But I can't add the cookies.

This might give you a lead. Previously I used a similar strategy to make a
WebRequest to a site and collect cookies which were stored in the .Net/Mono CookieStore. Then when loading a url in the UIWebView I copied those cookies over to the NSHttpCookieStorage.
public NSHttpCookieStorage _cookieStorage;
/// <summary>
/// Convert the .NET cookie storage to the iOS NSHttpCookieStorage with Login Cookies
/// </summary>
void DotNetCookieStoreToNSHttpCookieStore()
{
foreach (Cookie c in _cookies.GetCookies(new Uri(UrlCollection["Login"], UriKind.Absolute))) {
Console.WriteLine (c);
_cookieStorage.SetCookie(new NSHttpCookie(c));
}
}

Related

Share REST API session cookies with SFAuthenticationSession or SFSafariViewController

Actually, I'm calling REST API services using NSURLSession and I get the session cookies which provided headers. Now I want to share the same cookies with SFAuthenticationSession or SFSafariViewController and load the web page without login.
My Question: Share API cookies and load the web page without login.
Please refer below code to get the cookies from NSURLSession:
NSArray * all = [NSHTTPCookie cookiesWithResponseHeaderFields:[reponse allHeaderFields] forURL:url];
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookies:all forURL:url mainDocumentURL:nil];

How to protect Web API from CSRF attack if it called from cross domain client?

I have a Web API and that is called by cross domain client application developed in angular. How I can protect my Web API from CSRF attack.
I am using Token based authentication
I went through following article by Mike Wasson
https://learn.microsoft.com/en-us/aspnet/web-api/overview/security/preventing-cross-site-request-forgery-csrf-attacks
But in the above case also client and web api is running in same domain,
if it in different domain how we can pass AntiForgeryToken?
What about creating an endpoint which you can query when your application starts to get the tokens? Then send them along with every future request from the angular app.
public class AntiForgeryController : ApiController
{
[HttpGet]
public IHttpActionResult Get()
{
string cookieToken;
string formToken;
AntiForgery.GetTokens(null, out cookieToken, out formToken);
return Ok(new {cookieToken, formToken});
}
}

How can I secure simple HTML files using Azure AD?

I have a legacy static website that is just plain HTML and simple JavaScript for UI effects. There is no server side code, api, config files or anything in this website - just raw HTML files, CSS, pictures, etc.
The website will not be hosted in Azure. It will be on a local IIS server. If I pull the web site into Visual Studio, the "Configure Azure AD Authentication" wizard shows:
An incompatible authentication configuration was found in this project
().
How can I secure simple HTML files using Azure AD?
The Visual Studio "Configure Azure AD Authentication" wizard is intended for ASP.Net Web Apps and Web APIs.
In your case, what you are building is considered a "Single Page Application" or SPA. Even though you might have multiple pages, this term also applies to client side only web apps with no backend code.
For this, you should follow the Azure AD Javascript Single Page Application sample.
The gist of it is that you should us ADAL.js like shown in this sample's app.js, along the lines of:
// Configure ADAL
window.config = {
instance: 'https://login.microsoftonline.com/',
tenant: '[Enter your tenant here, e.g. contoso.onmicrosoft.com]',
clientId: '[Enter your client_id here, e.g. g075edef-0efa-453b-997b-de1337c29185]',
postLogoutRedirectUri: window.location.origin,
cacheLocation: 'localStorage', // enable this for IE, as sessionStorage does not work for localhost.
};
var authContext = new AuthenticationContext(config);
// Check For & Handle Redirect From AAD After Login
var isCallback = authContext.isCallback(window.location.hash);
authContext.handleWindowCallback();
$errorMessage.html(authContext.getLoginError());
if (isCallback && !authContext.getLoginError()) {
window.location = authContext._getItem(authContext.CONSTANTS.STORAGE.LOGIN_REQUEST);
}
// Check Login Status, Update UI
var user = authContext.getCachedUser();
if (user) {
//Do UI for authenticated user
} else {
//Show UI for unauthenticated user
}
// Register NavBar Click Handlers
$signOutButton.click(function () {
authContext.logOut();
});
$signInButton.click(function () {
authContext.login();
});
Note: There's also a Angular SPA sample.
The solution posted by Saca pointed me in the right direction, but adding the JS to every page was not a valid solution for me. There were thousands of HTML files, lots with no common JS file I could tack that ADAL code into. I would have had to find a way to insert that JS on all those pages.
My first solution was simply creating a normal .NET MVC app with the proper auth configured. Then I simply loaded this legacy content via an iFrame. This worked but was limiting for the users.
As Fei Xue mentioned in another comment, the next solution involved scrapping the iFrame but routing all requests for static files through a controller. Using this as a reference for understanding that: https://weblogs.asp.net/jongalloway/asp-net-mvc-routing-intercepting-file-requests-like-index-html-and-what-it-teaches-about-how-routing-works
The above solutions worked. However, eventually this app ended up as an Azure App Service and I simply turned on authentication at the app service level with just the pure html files.

How do I get this MVC5 client to Login via a remote WebApi2 app?

I'm creating an application in 2 parts. On one server is a .net Webapi2 using Owin. On another server is an MVC5 website with currently no login that will act as a front end for the api. It would also be a nice selling point to show that the app itself is an example of what a client can develop since it relies on the same api. I put the user authentication stuff in the api because I need 3rd parties to be able to develop their own front end apps using the api.
What I'm trying to accomplish (in theory)
I need to have a user submit their login information on the front end it will authenticate them via the resourceownergrant type and recieve results that allow the front end to create a cookie that includes the accesstoken and the identityuser / roles. As long as this cookie exists the mvc app would make calls to the api using the accesstoken. The MVC app and API would both be able to use the [Authorize] attribute.
What I have so far
I have the api up and working, I can post "grant_type=password&username=testuser&password=password123" and I receive something like this in json
{
"access_token":"-longasstokenhere-",
"token_type":"bearer",
"expires_in":1209599,
"userName":"testuser",
".issued":"Thu, 03 Apr 2014 16:21:06 GMT",
".expires":"Thu, 17 Apr 2014 16:21:06 GMT"
}
the web api's response also has a header of
set-cookie: -Long-assserializedcookiestuffhere-
My question is how to connect my mvc app.
in my mvc5 app I've got a startup for owin with this set in the configureauth
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
CookieName = "MyCookie",
LoginPath = new PathString("/Account/Login")
});
I have the [Authorize] attribute set on a test page that when I visit, it correctly redirects me to the login page. The piece I'm missing is how to make it so that clicking login makes the website post back to the api and create an Owin Cookie that the website will use to allow a user past the [authorize] attibute. I would also like it to contain the identityuser as well so the web app will automatically have the user info without having to post back to the api for it on every call. I dont know if I can grab the cookie from the return result somehow or what.
Also if theirs a better way I'm open to suggestions.
Heeelp!?
I had the exact same requirement. I tried to get the MVC5 CookieAuthentication to work, but it wouldn't let me use my own cookie value. But, your WebAPI should not return a set-cookie. WebAPI should be RESTful, and require the client to pass a bearer token on every request.
So, here's my solution. The username and password are sent to an external API, which return a JSON Web Token. The token from the API is stored in a cookie. You could do that in JavaScript, or in an MVC Account controller. That cookie is checked by the MVC app, and if it exists, the cookie indicates proof that the user is logged in to the MVC app, too.
In JavaScript, you pull that token from the cookie, and add it to all requests to the API in the Authorization header as Bearer token. Also, the MVC app can use the value of the cookie (the token) to access all of the user's claims. To logout, just expire the cookie.
First, wire up the app to use Bearer token, with our custom provider
// Api controllers with an [Authorize] attribute will be validated with JWT
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AllowedAudiences = audienceId.ToArray(),
IssuerSecurityTokenProviders = providers.ToArray(),
Provider = new CookieOAuthBearerProvider("MyCookieName")
{
LoginPath = new PathString("/Account/Login")
}
}
);
Now, I had to use a custom provider, because the Bearer token is stored in the cookie, not in the standard header. I also need to redirect to a login page, rather that simply issuing a 401.
public class CookieOAuthBearerProvider : IOAuthBearerAuthenticationProvider
{
public PathString LoginPath {get; set;}
public string CookieName { get; set; }
public CookieOAuthBearerProvider(string cookieName)
{
if(string.IsNullOrWhiteSpace(cookieName)) {
throw new ArgumentNullException("cookieName");
}
else {
this.CookieName = cookieName;
};
}
public Task ApplyChallenge(OAuthChallengeContext context)
{
if (this.LoginPath.HasValue)
{
context.Response.Redirect(this.LoginPath.Value);
}
return Task.FromResult<object>(null);
}
public Task RequestToken(OAuthRequestTokenContext context)
{
string token = context.Request.Cookies[this.CookieName];
if (!string.IsNullOrEmpty(token))
{
context.Token = token;
}
return Task.FromResult<object>(null);
}
public Task ValidateIdentity(OAuthValidateIdentityContext context)
{
// prove that the cookie token matches this site using context.Ticket.Identity
return Task.FromResult<object>(null);
}
}
Then, anywhere else in your MVC app, you can get the Claims by simply saying:
ClaimsPrincipal.Current

Help - MVC Certificate Security

We have an MVC 2/Entity Framework app that is a replacement/rewrite of an existing system. It's been using ASP membership for security during development but now we need to replace this so it is compatible with the customers existing security infrastructure, partly to allow both old and new systems to run side by side for a while and also because they already have a process and system to setup customers and we can't replace this yet.
The existing security centers around a table in the database that stores a certificate number mapped to a customerid. The customerid is then used to filter relevant data sent back in the UI.
My question is what is the most efficient way to go from certificate number to customerid. Each MVC controller action can grab the certificate number from the HTTPContext and do a look up in the security table to get the customerid but it seems inefficient to this on every controller action. The system could have 1000 concurrent users. We are thinking that it should work similiar to ASP.NET membership, where a username/password login generates a security token that is then placed in a cookie. Instead we would have the certificate replace the username/password login but it would still generate a security token.
The problem is we don't know enough about this system to determine how to go about it, or even if it's the best way forward. If anyone can offer any advice or pointers to how we would implement this it would be much appreciated.
Either
add it to the users Session once you look it up so its available upon login.
add it to the forms auth ticket (make sure you are patched for the POET vulnerability
or this could be forged)
or
cache the table in memory and do you lookups as required. this might be 'slightly' less efficient than session if you are already using the session because you will then be locking two collections (normal session usage) and the collection you store this in will have to be synchronized.
If you choose to store this information in the ticket you can create a CustomIdentity object to store this customer id in.
/// <summary>
/// Deserializes the forms auth cookie with our userid, companyid, etc.
/// </summary>
/// <param name="sender">
</param>
/// <param name="e"></param>
void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
HttpCookie authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
string encTicket = authCookie.Value;
if (!String.IsNullOrEmpty(encTicket))
{
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(encTicket);
CustomIdentity id = new CustomIdentity(ticket);
//Assign the roles. If they aren't available, get from the session.
//The problem is when we use this custom principal it seems our roles arent populated.
GenericPrincipal principal = new GenericPrincipal(id, new string[] { "User" });
HttpContext.Current.User = principal;
}
}
}
After each request is authenticated via the forms auth ticket you can deserialize this information into a Customer IIdentity object which can then be read throughout the application via:
int companyId = ((CustomIdentity)HttpContext.Current.User.Identity).CompanyId

Resources