google anaylitics visitor counter fail to return using API - google-analytics-api

I have written following code in a handler to get visitor counter in asp.net website
using Google.Analytics;
using Google.GData.Analytics; //v2.2.0.0
public class Visitor : IHttpHandler {
public void ProcessRequest (HttpContext context) {
AccountQuery feedQuery = new AccountQuery();
AnalyticsService service = new AnalyticsService("kiranaAnalytic");
service.setUserCredentials("myemailid#gmail.com", "mypassword");
DataQuery pageViewQuery = new DataQuery("https://www.google.com/analytics/feeds/data");//https://www.google.com/analytics/feeds/data
pageViewQuery.Ids = "ga:xxxx";
pageViewQuery.Metrics = "ga:visitors";
pageViewQuery.GAStartDate = "2014-05-01";//DateTime.Now.AddMonths(-1).ToString("yyyy-MM-dd");
pageViewQuery.GAEndDate = DateTime.Now.ToString("yyyy-MM-dd");
DataEntry pvEntry = service.Query(pageViewQuery).Entries[0] as DataEntry;
context.Response.ContentType = "text/plain";
context.Response.Write(pvEntry.Metrics[0].Value);
}
public bool IsReusable {
get {
return false;
}
}
}
It was working fine till yeaterday. But I am suddenly started getting following error.
"Google.GData.Client.GDataRequestException: Execution of authentication request returned"
Has anyone have idea about it or did google made some changes ?

This means there is something wrong with your authentication. You appear to be using Login and password which is called client login.
Client login which was discontinued / shutdown on April 20 2015 and I suspect turned off on Tuesday for Google Analytics. You can no longer use client login with Google Analytics API, you need to switch to Oauth2 or a service account. I recommend using the Google .net client library.
tutorial: Google Analytics API C# Oauth2

Google shutdown the old account-password authentication. You need to move your code to use Oauth.

Related

How do I create an AlertsClient from an Azure Active Directory secret? [duplicate]

My company is looking into reporting on Azure. We only want our customers to give us read only credentials for us to use. I did some research and it looks like Azure Active Directory does just that. So I'm looking to authenticate using a read only Azure Directory Application.
To get me started I was following this blog on using the Management API via Azure Active Directory.
https://msdn.microsoft.com/en-us/library/azure/dn722415.aspx
Aside from the approach show being very unfriendly, it doesn't work =(
I get this error after logging in as a global administrator:
"AADSTS90014: The request body must contain the following parameter: 'client_secret or client_assertion'."
Did some research and found this style of authentication was for native app and NOT web apps (despite what the blog post saying other wise..). So I made a tweak. My GetAuthorizationHeader now looks like this:
private static string GetAuthorizationHeader()
{
AuthenticationResult result = null;
var context = new AuthenticationContext("https://login.windows.net/" + ConfigurationManager.AppSettings["tenantId"]);
string clientId = ConfigurationManager.AppSettings["clientId"];
string clientSecret = ConfigurationManager.AppSettings["clientSecret"];
ClientCredential clientCred = new ClientCredential(clientId, clientSecret);
var thread = new Thread(() =>
{
result = context.AcquireToken(
"https://management.core.windows.net/",
clientCred);
});
thread.SetApartmentState(ApartmentState.STA);
thread.Name = "AquireTokenThread";
thread.Start();
thread.Join();
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the JWT token");
}
string token = result.AccessToken;
return token;
}
I am able to get the Access Token (yay). But now when I try to use this with the Azure Management library client I get this error:
"ForbiddenError: The server failed to authenticate the request. Verify that the certificate is valid and is associated with this subscription."
I double checked my permissions in my application. It looked good. I tried giving full access to everything to see if that would have made a difference.
I double checked my tenantId, clientId, and subscriptionId, all looked good.
I made sure the subscription I'm using is pointed to the AD my application is in.
I tried making a new secret key.
My guess is this is the issue:
However in this UI I am unable to select any values for that property. I'm unsure if this is the result of a bug or an unfinished feature.
Am I missing something here?
Thanks
Here's my full code for reference:
class Program
{
static void Main(string[] args)
{
var token = GetAuthorizationHeader();
var credential = new TokenCloudCredentials(ConfigurationManager.AppSettings["subscriptionId"], token);
using (var computeClient = new ComputeManagementClient(credential))
{
var images = computeClient.VirtualMachineOSImages.List();
}
}
private static string GetAuthorizationHeader()
{
AuthenticationResult result = null;
var context = new AuthenticationContext("https://login.windows.net/" + ConfigurationManager.AppSettings["tenantId"]);
string clientId = ConfigurationManager.AppSettings["clientId"];
string clientSecret = ConfigurationManager.AppSettings["clientSecret"];
ClientCredential clientCred = new ClientCredential(clientId, clientSecret);
var thread = new Thread(() =>
{
result = context.AcquireToken(
"https://management.core.windows.net/",
clientCred);
});
thread.SetApartmentState(ApartmentState.STA);
thread.Name = "AquireTokenThread";
thread.Start();
thread.Join();
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the JWT token");
}
string token = result.AccessToken;
return token;
}
}
EDIT:
Progress has been made. As I discussed with Gaurav, I needed to ditch the Azure Management Library because as of right now it does not seem to support Azure Resource Manager (ARM) API! So instead I did raw web requests. And it works as intended. If I remove role access off my AD Application I get access denied. When I have it I get back data.
One thing I'm not sure about is making it so my application is auto-adding to new resources.
Also, Is there a way to list Resource Groups that are accessible for my AD Application?
New code:
class Program
{
static void Main(string[] args)
{
var token = GetAuthorizationHeader();
string subscriptionId = ConfigurationManager.AppSettings["subscriptionId"];
string resourceGroupName = ConfigurationManager.AppSettings["resourceGroupName"];
var uriListMachines = string.Format("https://management.azure.com/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Compute/virtualmachines?api-version=2015-05-01-preview", subscriptionId, resourceGroupName);
var t = WebRequest.Create(uriListMachines);
t.ContentType = "application/json";
t.Headers.Add("Authorization", "Bearer " + token);
var response = (HttpWebResponse)t.GetResponse();
string result = "";
using (var reader = new StreamReader(response.GetResponseStream()))
{
result = reader.ReadToEnd();
}
//Original Attempt:
//var credential = new TokenCloudCredentials(ConfigurationManager.AppSettings["subscriptionId"], token);
//using (var client = CloudContext.Clients.CreateComputeManagementClient(credential))
//{
// var images = client.VirtualMachineVMImages.List();
//}
}
private static string GetAuthorizationHeader()
{
AuthenticationResult result = null;
var context = new AuthenticationContext("https://login.windows.net/" + ConfigurationManager.AppSettings["tenantId"]);
string clientId = ConfigurationManager.AppSettings["clientId"];
string clientSecret = ConfigurationManager.AppSettings["clientSecret"];
ClientCredential clientCred = new ClientCredential(clientId, clientSecret);
var thread = new Thread(() =>
{
result = context.AcquireToken(
"https://management.core.windows.net/",
clientCred);
});
thread.SetApartmentState(ApartmentState.STA);
thread.Name = "AquireTokenThread";
thread.Start();
thread.Join();
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the JWT token");
}
string token = result.AccessToken;
return token;
}
}
EDIT EDIT:
I figured out my hung up. Resources created in the OLD portal will get it's own distinct resource group.
From what I can tell you can not add a resource made in the old portal existing resource group (boooo). Resources created in the new portal will be able to assign the resource to an existing group (aka one that gives a role access to my AD Application).
This is such a mess! But at least I know what is going on now.
I believe you're on the right track as to why you're running into this problem.
Here's what's happening:
Essentially permission to execute Service Management API is a delegated permission and not an application permission. In other words, the API is executed in context of the user for which the token is acquired. Now you are getting this token for your application (specified by client id/secret). However your application doesn't have access to your Azure Subscription because the user record created for this application in your Azure AD is of type Service Principal. Since this Service Principal doesn't have access to your Azure Subscription, you're getting this Forbidden Error (I must say that the error is misleading because you're not using certificate at all).
There are a few things you could do:
Switch to Azure Resource Manager (ARM) API - ARM API is the next generation of Service Management API (SM API) and Azure is moving towards this direction only. It exclusively works off of Azure AD token. If possible, make use of that to manage your Azure resources (though you need to keep in mind that as of today not all Azure resources can be managed through ARM API). They way you do it is take your Service Principal and assign it to a particular role using new Azure Portal. Please see this link for more details on this: https://azure.microsoft.com/en-in/documentation/articles/resource-group-create-service-principal-portal/.
Use X509 Certificate - You can always use X509 Certificate based authorization to authorize your SM API requests. Please see this link for more details on that: https://msdn.microsoft.com/en-us/library/azure/ee460782.aspx#bk_cert. The downside of this approach is that the application (or whosoever has access to this certificate) will get full access to your Azure Subscription and can do everything there (including deleting resources).
Acquire token for a user instead of an application - This is another approach you can take. Essentially ask your users to login into Azure AD through your console application and acquire token for that user. Again, please keep in mind that this user must be a Co-Admin in your Azure Subscription and will have full access to your Azure Subscription as with SM API there's no concept of Role-based access control.

How to achieve Single Logout using Thinktecture Identity Server3 and OpenId owin middleware for multiple ASP.NET MVC applications

I have 2 ASP.NET MVC applications and I am using the OpenID middleware UseOpenIdConnectAuthentication to do the single sign on to both. Configuration is described as below. SSO works great. I login from application 1 and then I check if I am logged into application 2 too that connects to idserver, I can see myself logged in. Both the client applications now have the same id_token and token.
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
AuthenticationType = "oidc",
SignInAsAuthenticationType = "Cookie",
Authority = "<my-idserver-url>",
ClientId = "client1",
RedirectUri = "https://localhost:44360",
PostLogoutRedirectUri = "https://localhost:44360",
ResponseType = "id_token token",
//scopes from config file
Scope = ConfigurationManager.AppSettings.Get("Scope"),
Notifications = new OpenIdConnectAuthenticationNotifications
{
SecurityTokenValidated = n =>
{
var claims = n.AuthenticationTicket.Identity.Claims;
var accepted_claims = new[]{"name", "tenant", "email", "sub"};
var new_claims = claims.Where(x => accepted_claims.Contains(x.Type)).ToList();
new_claims.Add(new Claim("id_token", n.ProtocolMessage.IdToken));
new_claims.Add(new Claim("access_token", n.ProtocolMessage.AccessToken));
var ci = new ClaimsIdentity(new_claims, n.AuthenticationTicket.Identity.AuthenticationType, "email", "role");
n.AuthenticationTicket = new AuthenticationTicket(ci, n.AuthenticationTicket.Properties);
return Task.FromResult(0);
}
On clicking logout in the app, when the RedirectToIdentityProvider method is invoked in the clients, I am setting the id_token as the IdTokenHint as below:
RedirectToIdentityProvider = n =>
{
if (n.ProtocolMessage.RequestType == Microsoft.IdentityModel.Protocols.OpenIdConnectRequestType.LogoutRequest)
{
var user = n.OwinContext.Authentication.User;
if (user != null && user.Identity.IsAuthenticated)
{
var id_token_claim = user.Claims.FirstOrDefault(x => x.Type == "id_token");
if (id_token_claim != null)
{
n.ProtocolMessage.IdTokenHint = id_token_claim.Value;
}
}
}
return Task.FromResult(0);
}
Problem area > Single Logout:
Success Scenario:
When I logout from the application 1, it redirects to idserver and logs me out and redirects me back to application 1. On debugging I can see that the signout message in the logout method of the DefaultViewService is not null in this case. This works great.
Failure Scenario:
The problem is when I try to logout from application 2 instead of application 1(remember that I logged in from application 1), it does take me to the logout page at idserver, and I can logout. But it does not redirect back to the application 2 and stays on the idserver logged out page. On debugging I can see that the signout message in the logout method of the DefaultViewService is null in this case.
Is it probably because the id_token was originally issued to the application1?
What am I missing?
Do I need to handle this kind of scenario and somehow get hold of the client in identity server, that the user used, to actually logout(application 2)? and then probably issue a new SignoutMessage and put in the postlogout redirect Url for that client?
Or I got it all wrong and this should work automatically?
Update:
A blunder was to try this out with everything on IISExpress localhost on different ports, both clients(locahost, different ports) somehow get the same id_token and access token which shouldn't happen.
Moving out to the IIS hosting different sites solved this and now the applications can get their own individual id_token and access token.
I am still working on the Single Logout, exploring the iFrame approach.
I've been struggling on this myself for a few days. Googling pointed me to your question :)
This is what I've done which worked for me (Not sure if this is the correct approach):
Added both Client Uris in the PostLogoutRedirectUris for each client configuration:
PostLogoutRedirectUris = new List<string>()
{
"http://localhost:28560/",
"http://localhost:57311/"
}

How to get Facebook Friend List in ASP.NET?

I'm building an App with ASP.NET MVC 5 and Identity.
So far the login is working correctly.
Here the auth:
var fb = new FacebookAuthenticationOptions();
fb.Scope.Add("email");
fb.Scope.Add("friends_about_me");
fb.Scope.Add("friends_photos");
fb.AppId = "";
fb.AppSecret = "";
fb.Provider = new FacebookAuthenticationProvider() {
OnAuthenticated = async FbContext => {
FbContext.Identity.AddClaim(
new System.Security.Claims.Claim("FacebookAccessToken", FbContext.AccessToken));
}
};
fb.SignInAsAuthenticationType = DefaultAuthenticationTypes.ExternalCookie;
app.UseFacebookAuthentication(fb);
I'm trying to get the friends list. I've been looking for a few examples but none is working with this version of MVC 5.
My question is. How can I fetch all the friends with this version?
I don't want to use Javascript API, I want all the code in c# and then send to the view.
I think I just need to rewrite the login and store the access token in the session, and then simply call var client = new FacebookClient(TOKEN);
So how can I rewrite the login?
You've already got everything you need. The OnAuthenticated callback you've set adds a claim containing the access token for Facebook. You just need to pull the claim for the user:
var identity = (ClaimsIdentity)User.Identity;
var facebookClaim = identity.Claims.FirstOrDefault(c => c.Type == "FacebookAccessToken");
if (facebookClaim != null)
{
// access facebook API with `facebookClaim.Value`
}
And if it exists, then you can use the Facebook API to pull in their friends by making standard HTTP calls via something like HttpClient.

Pass a ADFS token to a custom STS service

I am testing a product that authenticates uses using a custom STS service. The way it used to work is, when a user hits the website using the browser, we issue a redirect to hit the STS service. the STS service authenticates the user by hitting AD and then issues a SAML token with some custom claims for the user. The website then hits the STS once again to get a ActAs token so we can communicate with the data service.
And I had a automation that would mimic this behavior and its working fine in production.
We are not modifying the STS to use ADFS to authenticate instead of hitting the AD directly. So now when I hit the website, the request gets redirected to a ADFS endpoint which authenticates the user and issues a token. Then we hit the custom STS service that would use the token to authenticate the user (instead of hitting AD), add custom claims and issue a SAML token for the user. We then generate a ActAs token using this to finally hit the data service.
I am trying to update my automation for this changed behavior. So what I am doing now is hit the ADFS service, obtain a token and pass the token to the STS service so it can issue me a SAML token.
I am quite an amateur when it comes to windows identity service so i am having hard time trying to get this work. I have successfully obtained the token (Bearer Token) from the ADFS but i cant figureout how to pass this token to my custom STS so it can issue me a SAML token.
Any help would be highly appreciated. Thanks!
here is the code i am using
public static SecurityToken GetSecurityToken()
{
var endPoint = new EndpointAddress(new Uri(#"ADFS endpoint"));
var msgBinding = new WS2007HttpBinding(SecurityMode.TransportWithMessageCredential, false);
msgBinding.Security.Message.EstablishSecurityContext = false;
msgBinding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
var factory = new WSTrustChannelFactory(msgBinding, endPoint);
factory.TrustVersion = TrustVersion.WSTrust13;
factory.Credentials.SupportInteractive = true;
factory.Credentials.UserName.UserName = "user";
factory.Credentials.UserName.Password = "pwd";
var rst = new RequestSecurityToken
{
RequestType = RequestTypes.Issue,
KeyType = KeyTypes.Bearer,
AppliesTo = new EndpointReference(#"custom STS endpoint")
};
return factory.CreateChannel().Issue(rst);
}
public static void GetUserClaimsFromSecurityTokenService(SecurityToken secToken)
{
var securityTokenManager = new SecurityTokenHandlerCollectionManager(string.Empty);
securityTokenManager[string.Empty] = SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection();
var trustChannelFactory = new WSTrustChannelFactory(Binding, new EndpointAddress("custom STS endpoint"))
{
TrustVersion = TrustVersion.WSTrust13,
SecurityTokenHandlerCollectionManager = securityTokenManager,
};
var rst = new RequestSecurityToken(RequestTypes.Issue)
{
AppliesTo = new EndpointReference("website url"),
TokenType = SamlSecurityTokenHandler.Assertion
};
var channel = (WSTrustChannel)trustChannelFactory.CreateChannel();
channel.Open(TimeSpan.FromMinutes(15));
try
{
RequestSecurityTokenResponse rstr;
SecurityToken token = channel.Issue(rst, out rstr);
var genericToken = (GenericXmlSecurityToken)token;
var req = new SamlSecurityTokenRequirement();
var handler = new SamlSecurityTokenHandler(req)
{
Configuration = new SecurityTokenHandlerConfiguration()
};
var newToken = handler.ReadToken(new XmlNodeReader(genericToken.TokenXml));
}
finally
{
channel.Close();
}
}

cakephp facebook api, FB->api('/me') returns empty value

I use Webtechnick Facebook plugin for cakephp 1.3 website. I implemented it about a year ago. And it worked fine until now. But today I found out that when I try to login(as a new user) it does not save facebook user data, because $this->Connect->user() (which result is taken from $this->FB->api('/me'), /plugins/facebook/controller/components/connect.php, line 194) returns nothing. I tried also, this facebook plugin on another cakephp 2.0 website, but the same thing was there.
I think, that there was some change in facebook api, because I did not absolutely make any change on the website, which could bring to that result.
this is user function in connect.php component
function user($field = null){
if(isset($this->uid)){
$this->uid = $this->uid;
if($this->Controller->Session->read('FB.Me') == null){
$this->Controller->Session->write('FB.Me', $this->FB->api('/me'));
}
$this->me = $this->Controller->Session->read('FB.Me');
}
else {
$this->Controller->Session->delete('FB');
}
if(!$this->me){
return null;
}
if($field){
$retval = Set::extract("/$field", $this->me);
return empty($retval) ? null : $retval[0];
}
return $this->me;
}
and my beforeFacebookSave() function in app_controller
public function beforeFacebookSave() {
$fbUser = $this->Connect->user ();
//debug($fbUser); // outputs nothing
$this->Connect->authUser ['User'] ['email'] = $fbUser ['email'];
$this->Connect->authUser ['User'] ['first_name'] = $fbUser ['first_name'];
$this->Connect->authUser ['User'] ['last_name'] = $fbUser ['last_name'];
return true;
}
Thank you !
There was a certificate change on Facebook that wasn't reflected in the SDK (because it used the old certificate). Since the plugin is based on PHP SDK, you should just fetch the latest version of the repo https://github.com/webtechnick/CakePHP-Facebook-Plugin. The author has pushed the commit to include the new PHP SDK with the new certificate.
https://github.com/webtechnick/CakePHP-Facebook-Plugin/tree/master/Vendor
Your error log should have a Facebook Exception due to SSL problems which chokes the API calls causing /me to return empty.
try this, it work for me
$infos = $facebook->api('/me?fields=id,first_name,last_name,picture,email');