I'm setting up a new server with windows Azure VM for a asp.net mvc 5 application. I'm able to open every page of the application without a problem with an exception of one controller. i.e. whenever I try to open a page belong to a specific controller, it prompts me for user name & password as below.
I use the same application in a different Windows Server 2016 VM without any issues.
I don't see any errors of the application/IIS logs either. I don't have any https requirements in the application.
What may be causing this behaviour?
namespace App.Controllers
{
public class ReportsController : BaseController
{
private readonly IReportRepository reportRepository;
public ReportsController(): this(new ReportRepository()){
}
public ReportsController(IReportRepository reportRepository){
this.reportRepository = reportRepository;
}
public ViewResult Action()
{
return View(reportRepository.All);
}
}
}
namespace App.Controllers
{
[Authorize]
public class BaseController : Controller
{
}
}
UPDATE: I renamed the ReportsController to AppReportsController and the issue disappeared.
i.e. I get the above prompt when I try to access
http://domain/Reports/Action
but not for
http://domain/AppReports/Action
Could you please someone explain to me what's going on here? Does it mean that "Reports" is reserved by the framework or something?
This is an authentication issue. In my case, it solved by below steps:
1- Go to IIS manager, in the left pane, expand the server root and select your web application from Sites node.
2- In the Home screen, go to IIS section and select Authentication.
3- Enable Anonymous Authentication.
4- Then, select Edit and set Edit Anonymous Authentication Credentials to Application pool identity.
I know this was an old post however I stumble on this one because I encountered the same error as the OP does.
I have solved this one in case there's someone encounters the same as this.
but the solution may vary depends if we have the same applications installed.
check if the web server / server has an installation of sql server.
check if there is reporting services installed.
remove / uninstall the reporting services from the application control panel
follow this link if you don't know how to remove the report service How to remove Report Service
Please check again if you still encounter the same error. Cheers!
The browser will tell you your connection to the site is not private if you don't use transport layer security (i.e. HTTPS) in your web application, and you are being asked to enter data - in this case your credentials. Doing this is dangerous because that data can easily be sniffed by a malicious person.
There is no reason in today's world to not have a secure site, I strongly recommend you get a certificate (they are free and super easy!)
Just don't use "Reports" use "Report" instead. Controller name ReportController not ReportsController. It'll be alright. I've faced the problem and this is the solution I've got.
We are trying to authenticate internal users via Azure AD when they visit certain pages. Our servers are not on site, so we are looking for an API where we can just pass the username and password of the user and receive whether they are in our organization and which groups they are apart of. It was possible in framework. Does such a thing exist for .NET Core?
UPDATE:
Thanks for replying! It seems to be giving me the authorization code now and now I'm trying to use this to get a token to then use that access token to get the user's groups (please correct me if I'm going about this the wrong way). My problem is I keep getting a bad request error. I've gone over the parameters a bunch and can't find what I'm missing. Here is my current set up of the API URLS, am I missing something?
string postData = $"{{\"grant_type\":\"{grant_type}\",\"client_id\":\"{client_id}\",\"code\":\"{code}\",\"redirect_uri\":\"{redirect_uri}\",\"client_secret\":\"{client_secret}\"}}";
string redirectUrl = $"https://login.microsoftonline.com/{tenant_id}/oauth2/authorize?client_id={client_id}&response_type={response_type}&redirect_uri={redirect_uri}&response_mode={response_mode}&resource={client_id}";
string requestUriString = $"https://login.microsoftonline.com/{tenant_id}/oauth2/token";
UPDATE 2: I figured out what was wrong, I was passing the post data as a Json String when it needed to be x-www-form-urlencoded.
I'm not completely sure this will solve your problem but you might want to have a look at the following .NET Core sample (with MSAL.NET): https://github.com/Azure-Samples/active-directory-dotnetcore-console-up-v2
This is with the usual disclaimer that we really don't recommend anybody to use username/password. There are other much better possibilities. For the full picture, see https://aka.ms/msal-net-scenarios
I will try and keep this as short as possible, although I may be leaving some things out, due to inexperience and/or lack of knowledge.
I have successfully been able to redirect from Website A to Website B, much like what was illustrated in the link C# - HttpWebResponse redirect to external URL (Thank You to everyone involved, this was very helpful)
The only problem is, that in Website B, after the redirection seems to have been successful, the system seems to ignore what happened , and redirect again back to it's Default home controller index Get Action result, and continues to Log in as if the Redirection never took place. I have removed everything that may cause this, in my opinion, like Attributes to check authentication etc.
Any help in this regard will be much appreciated.
According to your reference link( https://stackoverflow.com/questions/27503986/c-sharp-httpwebresponse-redirect-to-external-url), they try to create a single-sign-on system. Because they have 2 websites. The question of this link that how can they solve this problem with HtppWebRequest class. This is not possible ofcourse.
If you look at the answer section that I added on image, Author offer to use cookie sharing.
What is the correct solution to share authanctication info between different web site?
You should search about on Single Sing On Authantication methods.
Here is a few clue
OAuth(Google, Facebook)
SAML Protocol
JWt
may Jwt a bit hard way ;)
I just want to know if there is a naming standard on REDIRECT URIS for :
Twitter, LinkedIn, Microsoft, Facebook and Google when using OAuth 2.0?
Because, if I write my domain like that : http://domain.com/account/external-signin.aspx every external login stop working except Twitter and Facebook. The name account/external-signin.aspx is the real URL I'm working with and that I'm supposed to give to every external login.
So, Microsoft give this error:
We're unable to complete your request
Microsoft account is experiencing technical problems. Please try again later.
LinkedIn:
Invalid redirect_uri. This value must match a URL registered with the API Key.
And Google
400. That’s an error. Error: redirect_uri_mismatch
If I remove the page extension .aspx it seems to work although I deliberately write a wrong url like http://domain.com/sign-google, http://domain.com/sign-microsoft etc...
I'm working with MVC5 and C#.
I think I missed a few things ...
Thanks for your help
So finally, here is the correct answer:
It's not you that choose the redirect URL. You must write your domain.com/signin-{suppliername} in your app management.
Example:
Microsoft : https://domain.com/signin-microsoft
LinkedIn : https://domain.com/signin-linkedin
Google : https://domain.com/signin-google
Facebook and Twitter can work with your own redirect URL. Once successfully registered, the effect is immediate. Hope this can help somebody.
Karine
This error is denoting that you're having a miss match with the URL you're returning, and the return URL registered at the API Server. When you register your application, at the server, (for Google: https://code.google.com/apis/console) you have to make sure that the URLs being used would be matching.
After this, you will not get this error, I think on the server you've set this property to, http://domain.com/account/external-signin (without aspx; as you've said that this works without the extension but not with it). So try to change it on the server too.
For Linkedin append your url with "signin-linkedin".e.g. if your url is http://localhost:{portnumber}, make sure its is register in linked in as "http://localhost:{portnumber}/signin-linkedin" and this will do the trick.
Happy Codding :)
I've created a new MVC5 Web Application, and when I try to login with Google or Facebook, the ExternalLoginCallback Action in the AccountController is called, but GetExternalLoginInfoAsync() always returns null:
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
if (loginInfo == null)
{
return RedirectToAction("Login");
}
Because it's always null, it just redirects back to the login page and the process starts over. How can I fix this?
To get OWIN Google login to work properly on a standard Visual Studio 2013, ASP.Net MVC5 site, I had to:
Setup a Google OpenId account at https://console.developers.google.com/project
Set the callback URL there to blah/signin-google. Important notes on things you don't need to do:
You don't need to use HTTPS for Google to redirect back; you can even redirect back to plain http://localhost, no problem.
You don't need to setup anything for the redirect URL - no routes, Controller Actions or special permissions in Web.Config. The redirect URL is always /signin-google and OWIN handles this behind the scenes for you.
As an example, if your site was me.com, you might have these 3 callback URLs in the Google Developer Console:
http://localhost:53859/signin-google
http://test.me.com/signin-google
https://me.com/signin-google
The first one including whatever port number VS gave you for your project.
Enable the Google+ API. This is one hidden b**** of a gotcha and is the root cause of the problem in the question here - if you don't do this, it's easy to miss that the Request to /account/ExternalLoginCallback includes &error=access_denied, and that's because Google said no to a permissions request OWIN made for the user's Google+ basic profile. I can't tell whose fault this is, Google's or Microsoft's.
To enable the Google+ API in the Developers Console, click APIs on the left, hunt for Google+, click that and hit Enable. Yes you really do need to do that. You're hosed if you don't do that.
Add the ClientId and ClientSecret Google gave you in the Developers Console to Startup.Auth, but improve the code in the process to explicitly use OAuth2, and explicitly ask for the user's email address:
var google = new GoogleOAuth2AuthenticationOptions()
{
ClientId = "123abc.apps.googleusercontent.com",
ClientSecret = "456xyz",
Provider = new GoogleOAuth2AuthenticationProvider()
};
google.Scope.Add("email");
app.UseGoogleAuthentication(google);
That's it. That finally got it working.
Just want to reiterate one more time, there are a LOT of answers about this and issues like it where OWIN/Google isn't working, and nearly all of them are wrong for the current VS2013/MVC5/OWIN template.
You don't need to modify Web.Config at all.
You don't need to create any special Routes whatsoever.
You should not attempt to point /signin-google to a different place, or use a different callback URL, and you definitely shouldn't attempt to tie it directly to /account/externallogincallback or externalloginconfirmation, because those are both separate from /signin-google and necessary steps in the OWIN/Google process.
OK, I found out why it's null. You have to enable Google + API in the Google console. Also make sure the secret key is not concatenated with a space at the end after you paste it to your code. Why can't they return a normal error? I don't know.
It seems that Nuget package Microsoft.Owin.Security.Facebook version 3.0.1 no longer works with Facebook Login.
Update this package to the pre-release 3.1.0 version, you can use the following:
Install-Package Microsoft.Owin.Security.Facebook -Pre
As others correctly mentioned, most of the time that's because you do not have permission to the Google+ API so here is how to get permission for a project in Google API Manager to Google+ API
Step 1. Select You Project from the top combobox and go to Dashboard > Enable API
Step 2: Search for Google plus and select it
Step 3: Enable it!
if you return to dashboard for that project you can see the list of enabled API's for that project at the bottom
I got it to work by simply updating all the nugget package in the application and it worked.
I know it's silly, but after a long struggle, restarting IIS solved the issue for me.
This solved my problem:
Enable the Google+ API. This is a gotcha and is the root cause of the problem in the question here - if you don't do this, it's easy to miss that the Request to /account/ExternalLoginCallback includes &error=access_denied, and that's because Google said no to a permissions request OWIN made for the user's Google+ basic profile. I can't tell whose fault this is, Google's or Microsoft's.
To enable the Google+ API in the Developers Console, click APIs on the left, hunt for Google+, click that and hit Enable.
I did the following to get it working.
Logon to the developer portal, locate your application and do the following.
App details > App centered Listed Platforms > Select Yes for website
I ran in to this issue today and it turned out that I defined the remote cookie after I assigned the providers.
Make sure you place...
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
before...
app.UseFacebookAuthentication(
appId: "",
appSecret: "");
I wanted to contribute to this one also. I just recently got this working. I had the problem with the GetExternalLoginInfoAsync returning null but only in production.
After a lot of searching I finally found my answer it was simply a problem with my database. In production I had set the wrong connection string so it would not connect properly but it was basically silent about it. The only thing that happened was GetExternallLoginInfoAsync returned null. So check you database connection string if this happens!
Also on a sidenote, the only thing that was needed to get this working was:
Set up a project in the Google console
Enable Google+ API
Copy your client id and client secret to the Startup.Auth.cs file.
You do not have to enable HTTPS, you do not have to create custom routes. But make sure your database is working properly!
For those who are experiencing this problem for Web Api. Other solutions doesnt help AuthenticationManager.GetExternalLoginInfoAsync(); returns always null even google plus api is enabled.
use this custom function to get logininfo. obviously Microsoft has a bug for GetExternalLoginInfoAsync when requesting over web api.
private async Task<ExternalLoginInfo> AuthenticationManager_GetExternalLoginInfoAsync_WithExternalBearer()
{
ExternalLoginInfo loginInfo = null;
var result = await Authentication.AuthenticateAsync(DefaultAuthenticationTypes.ExternalBearer);
if (result != null && result.Identity != null)
{
var idClaim = result.Identity.FindFirst(ClaimTypes.NameIdentifier);
if (idClaim != null)
{
loginInfo = new ExternalLoginInfo()
{
DefaultUserName = result.Identity.Name == null ? "" : result.Identity.Name.Replace(" ", ""),
Login = new UserLoginInfo(idClaim.Issuer, idClaim.Value)
};
}
}
return loginInfo;
}
Although the answers above are all good, in my instance none of these worked - I'd checked and double checked the Google settings and agree with Chris Moschini that there's a lot of misleading info.
For me it was a 'doh moment when I realised that my Out of Process state service was not started! No errors (as a login was the first thing I was attempting after a reboot where the state service is set to manual start-up on the machine) just a Null from GetExternalLoginInfoAsync
Hope this helps someone else out.
After much searching and head scratching as well as following numerous red herring answers here on Stackoverflow I eventually went through all my options on my Google dev console and discovered a little blue [Enable] button on the Google+API overview page. I clicked this and hey presto it worked. Forget all the baloney you read about callback url and route configs, OWIN overrides the google default /signin-google redirect uri in any case and sends you back to ExternalLoginCallback. Just stick with the default implementation all will be good so long as you enable your Google+API.
It is true that you are going to need the Google plus Enabled. The big thing for me was the project URL. Open the properties window (View -> Properties Window) in VS and then right click the project and select properties. In small properties window copy your SSL URL, and then in the larger properties window select the Web tab and paste that URL in the Project URL.
Fixed the issue for me.
See in greater detail: https://learn.microsoft.com/en-us/aspnet/mvc/overview/security/create-an-aspnet-mvc-5-app-with-facebook-and-google-oauth2-and-openid-sign-on
For me I was migrating and old but working .NET 4.6.1 MVC website to core 1.1. Work stopped before I could get it working, when I picked it back up, I was then migrating to 2.x.
My problem was that the callback from Google was met with a 404 from my site. I thought it was supposed to hit AccountController.ExternalLoginCallback so I added a [Route(...)] to it and sure enough, Google's callback hit the action.
This then hit the null returned in this line (what kind of maniac returns a null?)
var externalLoginInfo = await this.SignInManager.GetExternalLoginInfoAsync();
I reverse engineered it to find under the hood its ultimately getting the handler for ExternalScheme which for my was the cookies handler!
It all seemed wrong and I felt somehow that the middleware was supposed to just intercept the callback URI so I removed my [Route(...)] and the 404 problem came back.
I then found that I need to add this during startup.
applicationBuilder.UseAuthentication();
This solves the 404 but gives another issue.
No authenticationScheme was specified, and there was no DefaultSignInScheme found.
By adding a default scheme here, I resolve the error above.
serviceCollection.AddAuthentication(IdentityConstants.ExternalScheme)
.AddGoogle(googleOptions => Configuration.Bind("OAuth2:Providers:Google", googleOptions))
.AddExternalCookie();
Now AccountController.ExternalLoginCallback is invoked again by some magic but I am back to the null return value.
I added this code above the offending line, which is essentially what is happening under the hood (looking at Microsoft's code on GitHub). Interestingly, h is of type CookieAuthenticationHandler and a has all my claims and information from Google inside!
var authHandler = this.HttpContext.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
var h = await authHandler.GetHandlerAsync(this.HttpContext, IdentityConstants.ExternalScheme);
var a = await h.AuthenticateAsync();
var externalLoginInfo = await this.SignInManager.GetExternalLoginInfoAsync();
Digging into GitHub and copy pasting internal code its running into my controller, I can see that it's failing to find ClaimTypes.NameIdentifier in my claims, this is the ProviderKey used later.
Hmm....
Concerned I was using old 1.x AccountController code with newer 2.x identity bits I did find some samples that still use this stuff, and some samples that use Razor Pages for it all, too. I'll continue with what I have.
So I'm next going to investigate mapping additional Google user JSON payload items into the claims. I think if my Google account ID (numeric, I guess) was mapped then everything would work.
https://learn.microsoft.com/en-us/aspnet/core/security/authentication/social/additional-claims?view=aspnetcore-2.2
Final Fix
I finally resolved the issue by adding a "claim action" to pull my Google identifier out of the JSON coming back from Google!
serviceCollection.AddAuthentication(IdentityConstants.ExternalScheme)
.AddGoogle(googleOptions =>
{
Configuration.Bind("OAuth2:Providers:Google", googleOptions);
googleOptions.ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "sub", "string");
})
.AddExternalCookie();
The sub field contains what eventually ends up in the nameidentifier claim and then into the ProviderKey that the AccountController wants.
In my case the solution was update Nuget package Microsoft.Owin.Security and Microsoft.Owin.Security.Google
All of the other answers didn't solve this for me, so if your in the same boat then make sure your registration controller action has the RequireHttps attribute:
// GET: /Account/LoginRegister
[AllowAnonymous]
[RequireHttps]
public ActionResult LoginRegister()
{
return View(new RegisterLoginViewModel());
}