Xamarin Forms - Access CookieStore from a WebView - xamarin

I'm creating a login page to a website and I want to use the cookies retrieved from this site to perform actions automatically
So I followed this article to access cookies from a given website,
From sniffing the packets between my device and the server, I received this very SetCookie:
Set-Cookie: AppCookie=COOKIEVALUE; expires=Tue, 13 Jul 2021 21:35:00 GMT; path=/; secure; samesite=lax; httponly
Although after retrieveing the Cookies for the site I don't get this cookie
Could anyone think of a reason for that?
Thanks in advance.

You could use custom renderer to retrieving the Cookies.
On Android:
var cookieHeader = CookieManager.Instance.GetCookie(url);
You could download the source file from the GitHub:
https://github.com/WendyZang/CookiesWebView
On iOS:
[assembly: ExportRenderer(typeof(WebView), typeof(CustomWebViewRenderer))]
namespace Sample.iOS
{
public class CustomWebViewRenderer : WkWebViewRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
NavigationDelegate = new CustomNavigationDelegate();
}
}
}
public class CustomNavigationDelegate : WKNavigationDelegate
{
public override void DidFinishNavigation(WKWebView webView, WKNavigation navigation)
{
webView.Configuration.WebsiteDataStore.HttpCookieStore.GetAllCookies((cookies) =>
{
});
}
}
}

Related

AdMob Banner wont show up, no error message with test ad and failed to load : 3 with real ad

I have a Xamarin Forms application on which I would like to advertise via Admob. If I set my real ad-id, I get Ad failed to load : 3. When I use the id of a test-ad, there is no error message in the console, but there is also no ad.
Ive tried connecting with firebase, which worked well, but didn't fix the problem. Ive also changed the language of the app and specified in the google play console settings that my App uses ads (even through it isnt live yet).
I used a custom renderer:
Class in forms:
namespace test7
{
public class AdMobView : View
{
}
}
android implementation:
[assembly: ExportRenderer(typeof(AdMobView), typeof(AdMobViewRenderer))]
namespace test7.Droid
{
public class AdMobViewRenderer : ViewRenderer<AdMobView, AdView>
{
public AdMobViewRenderer(Context context) : base(context) { }
string id = "ca-app-pub-xxxxxxxxxxxxx/yyyyyyyyyy"; //here was my real id and test id
private AdView CreateAdView()
{
var adView = new AdView(Context)
{
AdSize = AdSize.SmartBanner,
AdUnitId = id,
LayoutParameters = new LinearLayout.LayoutParams(LayoutParams.MatchParent, LayoutParams.MatchParent)
};
adView.LoadAd(new AdRequest.Builder().Build());
return adView;
}
protected override void OnElementChanged(ElementChangedEventArgs<AdMobView> e)
{
base.OnElementChanged(e);
if (e.NewElement != null && Control == null)
{
SetNativeControl(CreateAdView());
}
}
}
}
xaml:
<local:AdMobView x:Name="werbung" />
Any ideas how to fix this? Im lost :(
I suggest using this NuGet package. It sets everything up for you

HttpContext.Session.Abandon() doesn't work in MVC core. Session.clear doesn't log my user out

I get an error that says "ISession does not contain a definition for 'Abandon' and no accessible extension method 'Abandon' accepting a first argument of type 'ISession' could be found".
I have tried using session.clear but even after logging out if I open the website the user is logged in.
This is the error I get
This is how I have implemented Session in my ASP .NET CORE project:
Create a SessionTimeout filter:
public class SessionTimeout : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (context.HttpContext.Session == null ||!context.HttpContext.Session.TryGetValue("UserID", out byte[] val))
{
context.Result =
new RedirectToRouteResult(new RouteValueDictionary(new
{
controller = "Pages",
action = "SessionTimeout"
}));
}
base.OnActionExecuting(context);
}
}
Register this filter in your Startup.cs:
In your ConfigureServices method:
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(10);
});
In your Configure add:
app.UseSession();
And finally decorate your class/method with your filter like:
[SessionTimeout]
public class DashboardController : Controller
To destroy your session based on Logout event from your View:
public IActionResult Logout()
{
HttpContext.Session.Clear();
return RedirectToAction("Login", new { controller = "Pages" });
}
It seems my session is being stored in cookies and not getting cleared/deleted when used session.clear()
so I've used this and it seems to work like a charm.
foreach (var cookie in Request.Cookies.Keys)
{
if (cookie == ".AspNetCore.Session")
Response.Cookies.Delete(cookie);
}
HttpContext.Session.Clear() wasn't working for me on my live site in the Controller for my Account/Logout page.
I found out that setting a href of /Account/Logout/ was the problem. I changed my links to /Account/Logout.
If you're having Session problems in .NET Core 3.1 then try this. It may also account for why I couldn't get Cookie Authentication to work - I gave up in the end and switched to using Sessions.

Authentication with Facebook by using Xamarin.Auth

I am using Xamarin.Auth for login with facebook in my app(android/iOS) and all is going well but when successfully loged in, facebook profile is opening and not going back to my application. i want to redirect to my app's home page without showing facebook profile. i am following this tutorial and not get any success. i think i am not giving proper Urls of my app. Please give me suggestions.
your help will be appreciated thanks in advance.
here is my code of loginPageRenderer:
[assembly: ExportRenderer (typeof (FBLoginPage), typeof (LoginPageRendrerr))]
namespace FFirst_app.Droid
{
public class LoginPageRendrerr : PageRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
{
base.OnElementChanged(e);
// this is a ViewGroup - so should be able to load an AXML file and FindView<>
var activity = this.Context as Activity;
var auth = new OAuth2Authenticator (
clientId: "7b745e26dbb64e1a3a3bf6bfd33165bc", // your OAuth2 client id
scope: "basic", // the scopes for the particular API you're accessing, delimited by "+" symbols
authorizeUrl: new Uri("https://apps.facebook.com/myappppppp"),//("https://api.instagram.com/oauth/authorize/"), // the auth URL for the service
redirectUrl: new Uri ("http://www.facebook.com/connect/login_success.html")); // the redirect URL for the service
auth.Completed += (sender, eventArgs) => {
if (eventArgs.IsAuthenticated)
{
App.SuccessfulLoginAction.Invoke();
// Use eventArgs.Account to do wonderful things
App.SaveToken(eventArgs.Account.Properties["access_token"]);
string sessionToken = App.Token; // /* Authenticate the user with Facebook and fetch a session token */;
DateTime expiration = DateTime.Today; ///* The expiration time for the session token */;
string facebookId = Constants.FBAppId;
ParseFacebookUtils.LogInAsync (facebookId, sessionToken, expiration);
} else {
// The user cancelled
}
};
activity.StartActivity (auth.GetUI(activity));
}
}
}
I have found answer that i was wrong with URL's and now its working after when i changed 'authorizeUrl:' to "http://www.facebook.com/connect/login_success.html" and this URl also set on FB App as it is.So now my code is working properly.
On the Xamarin.Auth Getting Started page, it is mentioned that it is up to you to dismiss the UI on iOS:
auth.Completed += (sender, eventArgs) => {
// We presented the UI, so it's up to us to dimiss it on iOS.
**> DismissViewController (true, null); <**
if (eventArgs.IsAuthenticated) {
// Use eventArgs.Account to do wonderful things
} else {
// The user cancelled
}
};

Anti-Forgery Token + Web API (- MVC)

How to use Anti-Forgery Token With ASP.NET Web API without ASP.NET MVC?
Stephen Walther has this article of "Preventing Cross-Site Request Forgery Attacks with ASP.NET MVC" in http://stephenwalther.com/archive/2013/03/05/security-issues-with-single-page-apps ... but his solution includes MVC/Razor and in my front-end I don't planning to include it. And there are abundance articles like it, which the solution is adding #Html.AntiForgeryToken() but this cannot be my solution.
Later, I solved another issue, "the Same Origin policy": http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api, Could this be the solution to prevent the CSRF as well? I don't think so.
My problem was that I did not want to use MVC and just serve static html files backed by a WebApi. Here is what I did (Would this work?) Create a Http module that sets a random cookie value when serving any static file. For example:
public class XSRFModule : IHttpModule {
...
void context_EndRequest(object sender, EventArgs e) {
if (Path.GetExtension(HttpContext.Current.Request.Path) == ".html") {
HttpContext.Current.Response.Cookies.Add(new HttpCookie("XSRF-TOKEN", Guid.NewGuid().ToString()));
}
}
}
Then in your html page, use javascript to add the cookie value to a header when calling your api:
function callApi() {
xhr = new XMLHttpRequest();
xhr.open("GET", "api/data", true);
var regex = /\b(?:XSRF-TOKEN=)(.*?)(?=\s|$)/
var match = regex.exec(document.cookie);
xhr.setRequestHeader("X-XSRF-TOKEN", match[1]);
xhr.send();
}
finally, in your HttpModule, check that the cookie matches the header before processing any calls to your api:
void context_BeginRequest(object sender, EventArgs e)
{
if (HttpContext.Current.Request.Path.StartsWith("/api"))
{
string fromCookie = HttpContext.Current.Request.Cookies.Get("XSRF-TOKEN").Value;
string fromHeader = HttpContext.Current.Request.Headers["X-XSRF-TOKEN"];
if (fromCookie != fromHeader)
{
HttpContext.Current.Response.StatusCode = (int)HttpStatusCode.Forbidden;
HttpContext.Current.Response.End();
}
}
}
You need to set the HttpOnly flag to FALSE so that javascript from your domain can read the cookie and set the header. I am not a security expert, so I would like some feedback on this solution from some other members of the community.
EDIT
If you are using OWIN, you can use a global action Filter along with a middleware plugin:
Startup.cs
app.UseStaticFiles(new StaticFileOptions {
OnPrepareResponse = (responseContext) => {
responseContext.OwinContext.Response.Cookies.Append("XSRF-TOKEN", Guid.NewGuid().ToString());
},
FileSystem = "wwwroot"
});
XsrfFilter.cs
public class XsrfFilter : ActionFilterAttribute {
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext) {
string fromCookie = actionContext.Request.Headers.GetCookies("XSRF-TOKEN").FirstOrDefault()["XSRF-TOKEN"].Value;
string fromHeader = actionContext.Request.Headers.GetValues("X-XSRF-TOKEN").FirstOrDefault();
if (fromCookie == fromHeader) return;
actionContext.Response = new HttpResponseMessage(HttpStatusCode.OK);
actionContext.Response.ReasonPhrase = "bad request";
}
}

Configuring Windows Identity Foundation from code

I'm experimenting with "configuration-less WIF", where I want to accept a SAML2 token that is generated by Windows Azure's AppFabric STS.
What I'm doing is parsing checking the current request for token information, like so:
if (Request.Form.Get(WSFederationConstants.Parameters.Result) != null)
{
SignInResponseMessage message =
WSFederationMessage.CreateFromFormPost(System.Web.HttpContext.Current.Request) as SignInResponseMessage;
var securityTokenHandlers = SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection();
XmlTextReader xmlReader = new XmlTextReader(
new StringReader(message.Result));
SecurityToken token = securityTokenHandlers.ReadToken(xmlReader);
if (token != null)
{
ClaimsIdentityCollection claims = securityTokenHandlers.ValidateToken(token);
IPrincipal principal = new ClaimsPrincipal(claims);
}
}
The code above uses the SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection(); colection to verify and handle the SAML token. However: this does not work because obviously the application has not bee nconfigured correctly. How would I specify the follwing configuration from XML programmaticaly on my securityTokenHandlers collection?
<microsoft.identityModel>
<service>
<audienceUris>
<add value="http://www.someapp.net/" />
</audienceUris>
<federatedAuthentication>
<wsFederation passiveRedirectEnabled="true" issuer="https://rd-test.accesscontrol.appfabriclabs.com/v2/wsfederation" realm="http://www.thisapp.net" requireHttps="false" />
<cookieHandler requireSsl="false" />
</federatedAuthentication>
<applicationService>
<claimTypeRequired>
<claimType type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" optional="true" />
<claimType type="http://schemas.microsoft.com/ws/2008/06/identity/claims/role" optional="true" />
</claimTypeRequired>
</applicationService>
<issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35">
<trustedIssuers>
<add thumbprint="XYZ123" name="https://somenamespace.accesscontrol.appfabriclabs.com/" />
</trustedIssuers>
</issuerNameRegistry>
</service>
I was struggling with the same and found a working solution in WIF 3.5/4.0. Since maartenba's link seems to be dead, I wanted to post my solution here.
Our requirements were:
Configuration fully in code (as we ship a default web.config with the app)
Maximum allowed .Net version 4.0 (hence I am using WIF 3.5/4.0)
What I used to arrive at the solution:
Information about dynamic WIF configuration provided by Daniel Wu
here.
This
method
to register HTTP modules at runtime, explained by David Ebbo. I
also tried the more elegant method explained by Rick
Strahl,
but that unfortunately did not do the trick for me.
Edit 2016/09/02: instead of adding a separate "pre application start
code" class as in David Ebbo's example, the WIF-related HTTP modules
can also be registered in the static constructor of the
`HttpApplication' class. I have adapted the code to this somewhat
cleaner solution.
My solution needs nothing in web.config. The bulk of the code is in global.asax.cs. Configuration is hard-coded in this sample:
using System;
using System.IdentityModel.Selectors;
using System.Security.Cryptography.X509Certificates;
using System.Web;
using Microsoft.IdentityModel.Tokens;
using Microsoft.IdentityModel.Web;
namespace TestADFS
{
public class SessionAuthenticationModule : Microsoft.IdentityModel.Web.SessionAuthenticationModule
{
protected override void InitializePropertiesFromConfiguration(string serviceName)
{
}
}
public class WSFederationAuthenticationModule : Microsoft.IdentityModel.Web.WSFederationAuthenticationModule
{
protected override void InitializePropertiesFromConfiguration(string serviceName)
{
ServiceConfiguration = FederatedAuthentication.ServiceConfiguration;
PassiveRedirectEnabled = true;
RequireHttps = true;
Issuer = "https://nl-joinadfstest.joinadfstest.local/adfs/ls/";
Realm = "https://67px95j.decos.com/testadfs";
}
}
public class Global : HttpApplication
{
static Global()
{
Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(SessionAuthenticationModule));
Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(WSFederationAuthenticationModule));
}
protected void Application_Start(object sender, EventArgs e)
{
FederatedAuthentication.ServiceConfigurationCreated += FederatedAuthentication_ServiceConfigurationCreated;
}
internal void FederatedAuthentication_ServiceConfigurationCreated(object sender, Microsoft.IdentityModel.Web.Configuration.ServiceConfigurationCreatedEventArgs e)
{
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection coll = store.Certificates.Find(X509FindType.FindByThumbprint, "245537E9BB2C086D3C880982FA86267FBD66B9A3", false);
if (coll.Count > 0)
e.ServiceConfiguration.ServiceCertificate = coll[0];
store.Close();
AudienceRestriction ar = new AudienceRestriction(AudienceUriMode.Always);
ar.AllowedAudienceUris.Add(new Uri("https://67px95j.decos.com/testadfs"));
e.ServiceConfiguration.AudienceRestriction = ar;
ConfigurationBasedIssuerNameRegistry inr = new ConfigurationBasedIssuerNameRegistry();
inr.AddTrustedIssuer("6C9B96D90257B65B6F181C2478D869473DC359EA", "http://NL-JOINADFSTEST.joinadfstest.local/adfs/services/trust");
e.ServiceConfiguration.IssuerNameRegistry = inr;
e.ServiceConfiguration.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;
}
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
FederatedAuthentication.WSFederationAuthenticationModule.ServiceConfiguration = FederatedAuthentication.ServiceConfiguration;
}
}
}
Usage
My app is asp.net WebForms, running in classic pipeline mode and supports forms authentication as well as ADFS login. Because of that, authentication is handled in a common base class shared by all .aspx pages:
protected override void OnInit(EventArgs e)
{
if (NeedsAuthentication && !User.Identity.IsAuthenticated)
{
SignInRequestMessage sirm = new SignInRequestMessage(
new Uri("https://nl-joinadfstest.joinadfstest.local/adfs/ls/"),
ApplicationRootUrl)
{
Context = ApplicationRootUrl,
HomeRealm = ApplicationRootUrl
};
Response.Redirect(sirm.WriteQueryString());
}
base.OnInit(e);
}
In this code, ApplicationRootUrl is the application path ending in "/" (the "/" is important in Classic pipeline mode).
As a stable implementation for logout in mixed mode was not so easy, I want to show the code for that as well. Technically it works, but I still have an issue with IE immediately logging in again after logging out an ADFS account:
if (User.Identity.IsAuthenticated)
{
if (User.Identity.AuthenticationType == "Forms")
{
FormsAuthentication.SignOut();
Session.Clear();
Session.Abandon();
ResetCookie(FormsAuthentication.FormsCookieName);
ResetCookie("ASP.NET_SessionId");
Response.Redirect(ApplicationRootUrl + "Default.aspx");
HttpContext.Current.ApplicationInstance.CompleteRequest();
}
else
{
FederatedAuthentication.SessionAuthenticationModule.SignOut();
FederatedAuthentication.SessionAuthenticationModule.DeleteSessionTokenCookie();
Uri uri = new Uri(ApplicationRootUrl + "Default.aspx");
WSFederationAuthenticationModule.FederatedSignOut(
new Uri("https://nl-joinadfstest.joinadfstest.local/adfs/ls/"),
uri); // 1st url is single logout service binding from adfs metadata
}
}
(ResetCookie is a helper function that clears a response cookie and sets its expiration in the past)
Just a thought, no idea whether this works: Isn't there a way to get at the actual XML (which is empty in your case) and modify it at runtime through the classes in Microsoft.IdentityModel.Configuration?
Alternatively, some of the things in the XML you can modify at the time the sign-in request is sent out, in the RedirectingToIdentityProvider event by modifying the SignInRequestMessage
FYI: found a solution and implemented it in a module described (and linked) here: http://blog.maartenballiauw.be/post/2011/02/14/Authenticate-Orchard-users-with-AppFabric-Access-Control-Service.aspx

Resources