Google API authorization access denied while generating token - asp.net-mvc

I'm having some issues with google API while generating the token. The code works fine in the local machine but the publish version gives "Access is denied" error. I know that must be something related with the folder's permissions, but I don't know how to solve it. Actually our authorization function is like this:
public static DriveService AuthenticateOauth(string clientId, string clientSecret, string userName)
{
String folder = System.Web.HttpContext.Current.Server.MapPath("/App_Data/MyGoogleStorage/");
string[] scopes = new string[] { DriveService.Scope.Drive };
// here is where we Request the user to give us access, or use the Refresh Token that was previously stored in %AppData%
UserCredential credential = GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets { ClientId = clientId, ClientSecret = clientSecret }
, scopes
, userName
, CancellationToken.None
, new FileDataStore(folder)).Result;
DriveService service = new DriveService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Drive API",
});
return service;
}
The website is written in ASP NET MVC 5 and is hosted in Azure websites.
Thank you for your help.

The code works fine in the local machine but the publish version gives "Access is denied" error.
I have a same issue after I deploy the web application to Azure websites.
I refer to “Web applications (ASP.NET MVC)” section from this article to get user Credential and use DriveService, and I find it works fine on Azure websites.

I finally decided to use only my own drive account. So I created a token and I'm using it all the time. I followed these topics:
1.- Create a token for Google Drive API: https://stackoverflow.com/a/19766913/4965910
2.- Add Google API to MVC properly and use our token:
GoogleWebAuthorizationBroker in MVC For Google Drive Access
You must be careful, is easy to get stuck in some steps.
This only woks for ASP NET MVC applications with one drive account. I know is not solves the problem directly, this way is avoided it. Hope it helps.

Related

Broken AntiforgeryToken with Microsoft MSAL

I'm working with ASP.Net MVC and I have a problem using MSAL while authenticating a User. This is because, as we use AntiforgeryToken, when the user sign in in the page of Microsoft, the token breaks and we get an error related to the token.
My question is, is there a way to keep the token even after being redirected from Microsoft login page? Or can I recreate it?
I've search on other questions and google and found nothing.
Thank you.
Yes you can save the token in your application like this:
[AuthorizeForScopes(Scopes = new[] { "user.read" })]
public async Task<IActionResult> Profile()
{
// Acquire the access token.
string[] scopes = new string[]{"user.read"};
string accessToken = await tokenAcquisition.GetAccessTokenForUserAsync(scopes);
context.Token = accessToken;
}
Alternatively, you can explicitly acquire tokens by using the acquire-token methods as described in the core MSAL library. The MSAL wrapper provides the HTTP interceptor, which will automatically acquire access tokens silently and attach them to the HTTP requests to APIs.

GetExternalLoginInfo() returning null

I have registered my mvc app with https://apps.dev.microsoft.com/ and (when on localhost),after updating all NuGet packages managed to authenticate users (using a clientid and secret) using microsoft authentication - that works fine! lets forget the time wasted to discover that I had to use https://localhost:xxxx/signin-microsoft - thought I had to supply my callback method endpoint.
Now, I had to do the same thing however authenticating users with my app registered on Azure Active Directory in the section App Registrations.
Note: Users are not registered in azure but on a different domain however using microsoft authentication. I just changed the client id and secret to specify those generated on azure while registering the app. My Callback method is being accessed after signing in HOWEVER, the loginInfo object which I need to read the email of my user is NULL. I made sure i had the latest updates of packages, and i tried to search spending 3 days finding only applications which make use of tenants id, authority etc.
I just need to use individual accounts signing with microsoft authentication with an application registered on AAD (Azure active directory - registered apps section). I know it works because i've seen it working with php on other apps, but with microsoft code/libraries its not.
btw i tried adding scopes, calling synchronous to no good. I also tried inspecting the incoming data and its saying access denied and i'm pretty sure that client id and secret are ok. maybe the reply url is wrong? but any other callbacks i supply result in bad request and the callback method is at least being triggered. I also enabled "Sign Users In" and "Sign in and read users profile" permissions from azure as well. I'm running out of ideas. any help would be much appreciated. thanks
Code is the same code which is given to you when creating a new mvc web application using individual accounts i.e. In Startup.Auth.cs: i have this important part and other code
var myObj = new MicrosoftAccountAuthenticationOptions()
{
ClientId = "xxx",
ClientSecret = "xxx",
};
myObj.Scope.Add("openid");
myObj.Scope.Add("email");
// myObj.Scope.Add("User.Read");
app.UseMicrosoftAccountAuthentication(myObj);
In AccountController.cs i have this method which is initializing the request to microsoft
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult ExternalLogin(string provider, string returnUrl)
{
// Request a redirect to the external login provider
return new ChallengeResult(provider,
Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl
}));
}
and this (part of a) method which is handling the callback response:
[AllowAnonymous]
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
var loginInfo = await
AuthenticationManager.GetExternalLoginInfoAsync();
//...
}
ok solved. the solution i provided earlier in my question works for an application registered on https://apps.dev.microsoft.com/ . when i registered my app on AzureAD it had to be done in a different way following this method: https://learn.microsoft.com/en-us/azure/active-directory/develop/guidedsetups/active-directory-aspnetwebapp

Microsoft Graph API returning 403 to any request

I'm working on an application that, in this point, will retrieve the Office Groups that the logged in user is included and perform actions based on that info.
I'm using oAuth2.0 and the v2.0 token endpoint to get access without a user, and with the code below, I can provide administrator consent to the permissions (which were applied to the application permissions on the new Application Registration Portal https://apps.dev.microsoft.com/ and appear on the Enterprise Applications section on Azure), request the token to Azure and receive it, but even with the permissions applied and that token, I get a 403 response code (Insufficient privileges) from the Graph API to any request I try to perform.
The code for those actions is the following:
// Request Admin Consent
HttpRequestMessage adminConsentRequest = new HttpRequestMessage(HttpMethod.Get, "https://login.microsoftonline.com/" + TenantId + "/adminconsent?client_id="+ClientId+"&redirect_uri=https%3A%2F%2Flocalhost%3A44369%2FHome%2F");
var adminConsentResponse = await client.SendAsync(adminConsentRequest);
// Request Token
HttpRequestMessage tokenRequest = new HttpRequestMessage(HttpMethod.Post, "https://login.microsoftonline.com/"+TenantId+"/oauth2/v2.0/token") { Content = new FormUrlEncodedContent(tokenRequestPairs) };
var tokenResponse = await client.SendAsync(tokenRequest);
string tokenResponseBody = await tokenResponse.Content.ReadAsStringAsync();
var deserializedTokenResponse = (JObject)JsonConvert.DeserializeObject(tokenResponseBody);
string accessToken = deserializedTokenResponse["access_token"].Value<string>();
// Call Microsoft Graph API
HttpRequestMessage graphRequest = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0/me/memberOf");
graphRequest.Headers.Add("Authorization", "Bearer "+accessToken);
var graphResponse = await client.SendAsync(graphRequest);
string graphResponseBody = await graphResponse.Content.ReadAsStringAsync();
var deserializedGraphResponse = (JObject)JsonConvert.DeserializeObject(graphResponseBody);
Enterprise Application permissions on Azure
APP Registration Portal permissions
Can someone guide to any kind of mistake I'm making?
With the authorization token and the permissions applied, I can't see why would I get an AccessDenied response.
It's been more than 48 hours since I applied the permissions, so it's not a sync problem.
Update: So thanks to #juunas I managed to reapply the permissions and the token now shows all the permissions applied on the Application Portal (User.Read.All, Directory.Read.All and Group.Read.All), but the API still returns 403 status code (Authorization_RequestDenied).
I've tried another endpoint without the /me just to make sure that is not a reference problem, but it also returns 403 status code.
One thing that is funny is that the App was registered on the new app portal as I said, and it appears on Enterprise Applications on Azure, but not on my App Registrations, so I can only alter permissions on the new App Portal. It should be like this, since I'm using a new registration portal?
After a discussion in the comments, the problem was fixed by re-consenting the permissions similarly as shown in my blog post: https://joonasw.net/view/the-grant-requires-admin-permission (though it is written for v1).
To run admin consent again, you need to add prompt=admin_consent to the authorize URL.
Okay, so a few minutes after the update on the original post, the token was accepted by the endpoints.
The only problem is that the graph API does not recognize the ID of the user logged in to use the /me endpoints, but I bypassed that using the /{group-id}/members endpoint (in my case, it's not how I wanted but solves my problem).
Thanks #juunas for the help!

Asp .Net Identity 2 OAuth via Google+ error in production server

I am getting the problem when I use Asp .Net Identity 2 connect Google+. Currently, my website connect Google+ via OAuth API 2 and use Claim Identity store some information of users. I was setup fine in running localhost with https. But the problem appear when I deploy my website into production server. After use accept to provide permission for my website to get his information, Google+ callback my website with url /signin-google. And after that, ASP .Net MVC automatically redirect to ExternalCallBack action but it is get error ?error=access_denied. I have capture the network and see information below:
In url callback signin-google:
signin-google?state=nNABsQBmwoPILh1mViOUIqzDcxQIS3HVZx2jtrSYCwd-ifMn4bDgBV1H1qdewFZx5Lz1c35ZZEpUem9jDTUrKlzWDuV-MwTQ3Tesx66PEjWdQQHo0QPJHX_bRMHqgN-Ad1whLs4iUyUSCH39oeTvYg3Cx6O0_v7Sc5GaUujHgr6xW1jw8EImhWJgnFGXgkAjD5hOtr7RoYO23xJyw0AIyuWnyx1gInJndWKvL-eqWPD9BtRaNe3nhWF5NGEG_2Ir&code=4/OEwsZCeeDPKrN5Dls3Uu-Q0wacdMqlhdbb8B1P__8X8.MmSgAQ_-cmIRgrKXntQAax20FxCmlQI
Asp.Net.Collrelation.Google nXgdr60bDh6tfivnvc6NA6ubz1K9zwjOqgrBBQgsitE
In URL callback external-login:
external-login-callback?error=access_denied
Hope you help me.
*Edit:
This is my code in Startup.Config.cs
var googleOpt = new GoogleOAuth2AuthenticationOptions()
{
ClientId = "xxxxxxxxpm0il.apps.googleusercontent.com",
ClientSecret = "xxxxxxxx",
Provider = new GoogleOAuth2AuthenticationProvider()
{
OnAuthenticated = (context) =>
{
context.Identity.AddClaim(new System.Security.Claims.Claim("GoogleAccessToken", context.AccessToken));
return Task.FromResult(o);
}
}
};
googleOpt.Scope.Add("https://www.googleapis.com/auth/plus.login");
googleOpt.Scope.Add("https://www.googleapis.com/auth/plus.profile.emails.read");
googleOpt.SignInAsAuthenticationType = DefaultAuthenticationTypes.ExternalCookie;
app.UseGoogleAuthentication(googleOpt);
And in my account controller I use default code of Asp .Net MVC 5.2
I had the same issue and had to enable the Google+ API in the Google Developer Console.
If this is turned off, it will not work. As soon as I turned it on, everything was fine.

ASPNet Identity Authentication MVC5 Client web site->Auth Server-> Web API server

I'm a newbie for ASPnet identity services and we require a following requirement.
Following is the architecture setup
1. Appserver
Appsever having
a. Entity Framework
b. ASP.Net Web API2 Odata services
c. Authorization server
2. Webserver
ASP.Net MVC 5 application (Client which access the App server)
The flow needs to be
MVC5 Cleint application having a login / Register form
While register / login the information needs to send to the authorization server int he app server, Authorize and creating the claims using Identity Services.
Once the Identity has been created in the Authorization server, the client application should logged in
I'm aware of getting bearer token from authentication server and that will be used as header information to access the API service
All we are lacking is the MVC client application should use the same identity claims that have created in the Authorization server.
Is there any way to access the claims which are created in the auth server.
I have got some samples about how to authenticate in the auth server and receiving token though OWIN and from this token we can access the API securely but I need of the client web application needs to sign in based on the token
I have gone through the following links
http://blogs.msdn.com/b/webdev/archive/2013/09/20/understanding-security-features-in-spa-template.aspx
Also, I require to add claims when ever it requires after login as well
I have resolve this issue as follows, but I'm not sure this is the effective method
Once log-in and retrieve the bearer token (this token should assigned with claims identity already such as username, role .. etc)
In the web api AccountController, need to create a method to retrieve the default claims which requires for client web application. Please check the follows
[Authorize]
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("UserInfo")]
public UserInfoViewModel GetUserInfo()
{
var firstname = ((ClaimsIdentity)User.Identity).Claims.Where(c => c.Type.Equals("FirstName")).SingleOrDefault();
var lastname = ((ClaimsIdentity)User.Identity).Claims.Where(c => c.Type.Equals("LastName")).SingleOrDefault();
var IsApproved = ((ClaimsIdentity)User.Identity).Claims.Where(c => c.Type.Equals("IsApproved")).SingleOrDefault();
var userinfo = new UserInfoViewModel
{
UserName = User.Identity.GetUserName(),
FirstName = firstname.Value.ToString(),
LastName = lastname.Value.ToString(),
UserApproved = Convert.ToBoolean(IsApproved.Value.ToString()),
HasRegistered = externalLogin == null,
LoginProvider = externalLogin != null ? externalLogin.LoginProvider : null
};
return userinfo;
}
From the client, this actin will be called through the token as a header.
Once we have got the information (is in Json string format) needs to serialize with the UserInfoViewModel class (user defined viewmodel is based on the info we require and send from webapi account) with javascript serializer
Using these viewmodel information, assign them to local storage and using (cookies for my case) as a identity at local
keep logout webapi too when ever you logs out from web app.
Please let me know if you need more info or code

Resources