Google analytics, emulate campaign hit serverside - google-analytics

I am involved in a project where people needed to link + track users going to a third party site.
They did this by setting up a redirect page that funnels users on to the third party site, while setting up tracking using Google analytics and building campaign urls that point to the redirect page.
I want to set up a quicker redirect page by handling the analytics serverside. It speeds up well, but to be able to transition, I need to somehow emulate passing through their pass through page.
I'm using asp net core, but this should be fairly lagnuage agnostic, since I'm using the google api
[HttpGet]
public RedirectResult Get()
{
[...]
//send official analytics async
Task.Run(() => SendParametersToGoogle(BuildPageViewUrl(_config["officialAnalyticsId"], _config["officialRedirectUrl"], "TCI", source, medium)));
return Redirect(_config["redirectUrl"]);
}
private static string BuildPageViewUrl(string googleId, string documentLocation, string campaignName, string campaignSource, string campaignMedium)
=> $"v=1&tid={UrlEncode(googleId)}&t=pageview&dl={UrlEncode(documentLocation)}" +
$"&cn={UrlEncode(campaignName)}&cs={UrlEncode(campaignSource)}&cm={UrlEncode(campaignMedium)}";
private static void SendParametersToGoogle(string parameters) => HttpClient.PostAsync(new Uri("https://www.google-analytics.com/collect"), new StringContent(parameters, Encoding.ASCII));
I get an OK response, but the events doesn't show up in google analytics under Acquisition->Campaigns->All Campaigns.
I have waited 3 days to allow for data processing time.
Any ideas?

Your generated call to the Measurement Protocol seem to be missing Client ID or User ID. The documentation claims one of them as required, to identify the visitor.
I'm not sure, why you get successful response, as Client ID is also marked as a mandatory field by the Hit Builder tool:

Related

Anti-Forgery Token issue: not on login or logout, but upon return to website from payment processor

I have got the weirdest issue that I cannot seem to properly debug.
Current project:
Asp.NET 4.7.2
MVC 5
When a user logs in, they are able to log back out and back in without any issues. No token issues there. Timeout is for 60 minutes.
However, on this site there is a “cart” that users can put some very limited things into and pay for. The payment button moves them over to the payment processor (a hosted payment page), who then takes CC info and processes that payment. Once the payment is complete (or it fails), the user is shunted back to a specific page on the website, also within their account. The only thing this landing page does is look for a few GET values that the payment processor has added to the end of the URL, and records those values to the database (thereby recording the item in the cart as having been paid).
However, about one-third of people who get sent back from the payment processer - after a successful payment - are experiencing the
The provided anti-forgery token was meant for a different claims-based user than the current user.
error message.
So to be clear:
The user goes to their cart, clicks on “Process Cart”.
The user gets shunted over to the payment processor’s hosted payment page, leaving the current site entirely.
The user makes payment on the payment processor’s hosted payment page.
The payment processor processes the payment, and regardless of whether it fails or not, sends the user back to a specific landing page on the website that is behind the login and within their account.
The error occurs at this point, when they are sent back to this landing page.
My code on this landing page is exceedingly simple:
[HttpGet]
public async Task<ActionResult> Processed() {
var responseCode = Request.QueryString["RESPONSECODE"];
var orderId = Request.QueryString["ORDERID"];
var customField = HelperExtensions.GetGuid(Request.QueryString["CUSTOMFIELD1"]);
var amount = Convert.ToDecimal(Request.QueryString["AMOUNT"]);
var cardNumber = Request.QueryString["CARDNUMBER"];
var approvalCode = Request.QueryString["APPROVALCODE"];
var uniqueRef = Request.QueryString["UNIQUEREF"];
var dateTime = Convert.ToDateTime(Request.QueryString["DATETIME"]);
if(string.Equals(responseCode, "A")) { // Transaction approved
//Process these values and insert them into the DB to mark the cart as having been paid.
}
//Send *everyone* to the View, with appropriate messages served up by the view’s model depending on the responseCode.
return View("Processed", new ProcessedViewModel(transactionId, responseCode, orderId, amount, cardNumber, approvalCode, uniqueRef, dateTime, additionalErrors));
}
I have already tried verifying this with a dummy account on the site, and manually generating a return URL that the landing page can “process”, but unless I am willing to rack up several thousand dollars in CC fees myself (these are membership fees, in the several hundred dollar range), I cannot work with a full round trip.
Please note that this issue is explicitly not showing up during login or logout. Or with a login immediately after a logout. It is only showing up after the user is sent back to the landing page from the payment processor.
Also please keep in mind: fully two thirds of users are not experiencing this bug. Only about one third of them are. So this appears to be a transient issue, and I have not yet tracked down the differences between the successful catches on the landing page and those catches that fail.
I have gone so far as to decorate all controllers with:
[NoCache]
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
The first one being a no-cache attribute I found elsewhere on StackOverflow:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class NoCacheAttribute : ActionFilterAttribute {
public override void OnResultExecuting(ResultExecutingContext filterContext) {
filterContext.HttpContext.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
filterContext.HttpContext.Response.Cache.SetValidUntilExpires(false);
filterContext.HttpContext.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
filterContext.HttpContext.Response.Cache.SetNoStore();
base.OnResultExecuting(filterContext);
}
}
Despite this addition, the errors have not ceased (although there hasn’t been enough payments yet to determine if the ratio of token errors has changed).
Anti-Forgery Tokens work with cookies, If the web browser is blocking the cookies it will cause this ERROR.
"The provided anti-forgery token was meant for a different
claims-based user than the current user."
Create an action that will log cookies that are blocked to compare to users with this issue.
Anti-Forgery Tokens are there to prevent against CSRF, assuming you have the customer leaving the site to Pay and returning to the users account without a cookie.
Create a custom Anti-Forgery Token so when browser cookies are disabled then token will be stored in session and also compare from session.
Take a look at this site.
Hope this helps

Twilio voice recording in ASP.Core

I'm building a new application and one of the its function is communication between seller and customer. For this reason I want to use Twilio API.
So let's imagine we have two person: seller and customer, and they are going to communicate. My idea is that these two person shouldn't know real phone number each other, so I buy two phone numbers from Twilio, one for seller and one for customer and connect them with real phones in my app. For convenience I've created TwiML App in Twilio console and set REQUEST and STATUS CALLBACK URLs for Voice calls, these urls are pointed to Webhook in my app. My application is based on .Net Core, but I still use full .Net4.6 framework, because there are no some .dlls for .Net Core and seems Twilio helpers for C# have also been built for full .Net framework. Any way, my webhook method looks like:
[HttpPost("call")]
public IActionResult IncomingCall(VoiceRequest request) {
// some logic
VoiceResponse response = new VoiceResponse();
response.Dial({real_seller_number}, callerId: {virtual_customer_number}, record: "record-from-ringing-dual");
return Content(response.ToString(), "application/xml");
}
Here, let's imagine I'm customer, I want to call seller, I call its virtual Twilio number, Twilio makes a request to this webhook and it make a call to real seller's number from virtual customer number. This is OK and works as intended.
When the call ends, Twilio makes a request to STATUS CALLBACK url, and this methos looks like:
[HttpPost("call/callback")]
public IActionResult IncomingCallCallback(StatusCallbackRequest request) {
// some logic
return Ok("Handled");
}
In a first method you can see I want to record conversation for internal reason, and I expected RecordingSid and RecordingUrl in second method, but I always get them null. I can see the recording in Twilio console, but cannot get them via API, that's my problem. I spent a lot of time and read a lot of docs, but didn't find clear explanation how to do it right. Can someone help me?
Twilio developer evangelist here.
When recording calls the recording might not be ready by the time you receive the statusCallback request. Instead you should set a recordingStatusCallback URL which will be called when the recording is complete and ready.
[HttpPost("call")]
public IActionResult IncomingCall(VoiceRequest request) {
// some logic
VoiceResponse response = new VoiceResponse();
response.Dial({real_seller_number},
callerId: {virtual_customer_number},
record: "record-from-ringing-dual",
recordingStatusCallback: {url_in_your_application_that_processes_recordings}
);
return Content(response.ToString(), "application/xml");
}

Use Firebase.com authenication without forcing the user to create an account

I am developing a small App to allow the user to store To-Do items. I am using Firebase ass my backend.
For the first iteration I don't want the user to have to sign-up, but still only see it's own data. My first thought was just to use the anonymous authentication, store the UID an reuse it everytime the app is started. This is not possible since the session is gonna time out at some point and the user would get a new UID the next time.
I of course want to make sure that a user can only see it's own items using the Firebase Security & Rules.
The idea would be to save the items like this: app.firebase.com/user/123456/todo-item
123456 beeing the unique ID of the user.
Can I create a unique identifier myself and still use the Firebase Security & Rules?
You would have to run your own custom authentication solution.
When the Activity loads, you'll have to make a request to your server. Then on the server you can create tokens for a user when they load the page:
// These payload properties are accessible
// by Security Rules which is awesome
Map<String, Object> payload = new HashMap<String, Object>();
payload.put("uid", "uniqueId1");
payload.put("some", "arbitrary");
payload.put("data", "here");
TokenGenerator tokenGenerator = new TokenGenerator("<YOUR_FIREBASE_SECRET>");
String token = tokenGenerator.createToken(payload);
There's more packages than just Java, so read the docs.
Then when you deliver the token back to the user, you would need to store the token locally.
Once the token is stored, you can retrieve it and authenticate.
Firebase ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com/");
ref.authWithCustomToken(AUTH_TOKEN, new Firebase.AuthResultHandler() {
#Override
public void onAuthenticationError(FirebaseError error) {
System.err.println("Login Failed! " + error.getMessage());
}
#Override
public void onAuthenticated(AuthData authData) {
// authenticated
}
});
You probably aren't thrilled about having to run a server, but take a look at using Google AppEngine with the Firebase JVM client. It's pretty easy and handles the server maintenance for you.
This tutorial by a former Google Cloud tools member, and current Firebase team member is a great place to start.

Spring Social Facebook

I am developing with Spring Social and Thymeleaf from the quick start example, but I realised that it only supports one Facebook object per controller. This means the sample can't provide support for multiple users and I am guessing it has to do with the #Scope of the variable. Its runs in a Spring boot container and I wonder how I can configure this so that each session has its own Facebook object.
As you suggested, the Facebook object should be configured with request scope. If you're using the configuration support and/or Spring Boot, then it will be request scoped. Therefore, even though the controller is injected once with a Facebook instance, that instance is really a proxy that will delegate to a real FacebookTemplate instance that is created at request time for the authenticated user.
I can only assume that you're referring to the getting started guide example at http://spring.io/guides/gs/accessing-facebook/. In that case, it's using the most simple Spring Boot autoconfiguration possible for Spring Social, which includes a basic (yet not intended for production) implementation of UserIdSource which always returns "anonymous" as the user ID. Therefore, after you create the first Facebook connection, the second browser tries to find a connection for "anonymous", finds it, and gives you an authorized Facebook object.
This may seem peculiar, but it is an example app intended to get you started...and it does that. All you need to do to get a real UserIdSource is to add Spring Security to the project. That will tell Spring Social autoconfiguration to configure a UserIdSource that fetches the current user ID from the security context. This reflects a more real-world use of Spring Social, albeit obviously more involved and beyond the scope of the getting started guide.
But you can look at https://github.com/spring-projects/spring-social-samples/tree/master/spring-social-showcase-boot for a more complete example of Spring Social within Spring Boot.
Spring Boot autoconfigures a lot of things behind the scenes. It does autoconfigure the Facebook, LinkedIn and Twitter properties and sets up the connection factories for social providers.
However, the implementation of UserIdSource always returns “anonymous” as the user ID. Once the first Facebook connection is established the second browser will try to find a connection for “anonymous” which it finds and gives you an authorised Facebook object.
#Configuration
#EnableSocial
#ConditionalOnWebApplication
#ConditionalOnMissingClass("org.springframework.security.core.context.SecurityContextHolder")
protected static class AnonymousUserIdSourceConfig extends SocialConfigurerAdapter {
#Override
public UserIdSource getUserIdSource() {
return new UserIdSource() {
#Override
public String getUserId() {
return "anonymous";
}
};
}
}
Solution
The solution is to override the “anonymous” as the UserId for each new user/session. So for each session, we can simply return a SessionID, however, it may not be unique enough to identify users, especially if it’s being cached or stored somewhere in a connection database.
#Override
public String getUserId() {
RequestAttributes request = RequestContextHolder.currentRequestAttributes();
String uuid = (String) request.getAttribute("_socialUserUUID", RequestAttributes.SCOPE_SESSION);
if (uuid == null) {
uuid = UUID.randomUUID().toString();
request.setAttribute("_socialUserUUID", uuid, RequestAttributes.SCOPE_SESSION);
}
return uuid;
}
The solution for above problem has been talked about in detail over here

Manually associate session with current request asp.net MVC

I have a MVC 5 asp.net website where I need to expose a number of REST APIs to a stand-alone mobile client. The rest of the site is using Forms based security where it sets the ASP.NET_SessionId as a cookie, and that is used to authenticate the user with the request after they log in. With my mobile application, I am not able to use the cookie method because of the cross-doman issue. What I would like to do is add a header "X-SessionId" with the value of the ASP.NET_SessionId, then on the server side, have a filter that looks for that field, and if it is present, associates the request with the given session. (Client will log in with an AJAX POST call which will return the ASP.NET_SessionId upon successful login).
Is this possible?
Something like this?
public sealed class CustomSecurityAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext == null)
throw new ArgumentNullException("filterContext");
if (string.IsNullOrEmpty(filterContext.HttpContext.Request.Headers["X-SessionId"]) && IsAuthenticated(ilterContext.HttpContext.Request.Headers["X-SessionId"]))
filterContext.Result = new HttpNotFoundResult();
}
private bool IsAuthenticated(string sessionId)
{
// get your user details from your database (or whatever)
var user = new UserRepository().Get(sessionId);
if (user == null)
return false;
// build up an identity, use your own or out of the box.
FormsIdentity itentity = new MyIdentity(user);
// Set the user
filterContext.HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(itentity , user.Roles);
return true;
}
}
You are going to have to store current sessions in your database, so for example when a user logs in grab the sessionid and stick it in the db, so you know they have 1..n current sessions.
Then you can look it up as part of your authentication.
Edit:
Let's take a step back, never mind cookies and sessions for the moment.
You have a website and a restful api, they both servce different purposes and clients and have different security requirements.
So what are the most common options for securing your Api?
Basic authentication.
Most restful APIs require a username/password to be sent through with each request, as part of the headers or in the request itself.
An authentication token
You can provide a token associated with a user account (a guid could suffice) when requests are made you check for the token.
Using an existing protocal like OAuth
I would recommend using these common scenarios to be sure you don't miss something and open your self up to security vulnerabilities.
Is there a reason you can't use any of these?

Resources