Have a weird thing happening here.
I have built an ASP.NET MVC5 website, and have local accounts working fine via ASP.NET Identity.
I am now trying to enable external authentication, but have some weirdness happening.
I'm certain I've followed the right steps. I have this in my Startup.Auth.cs:
public void ConfigureAuth(IAppBuilder app)
{
// Enable the application to use a cookie to store information for the signed in user
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login")
});
// Use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Uncomment the following lines to enable logging in with third party login providers
//app.UseMicrosoftAccountAuthentication(
// clientId: "",
// clientSecret: "");
//app.UseTwitterAuthentication(
// consumerKey: "",
// consumerSecret: "");
//app.UseFacebookAuthentication(
// appId: "",
// appSecret: "");
app.UseGoogleAuthentication();
}
When the user clicks on the link to logon with Google, the ExternalLogin method is called:
[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 }));
}
Which I have verified via debugging gets into the ExecuteResult method of the ChallengeResult class:
public override void ExecuteResult(ControllerContext context)
{
var properties = new AuthenticationProperties() { RedirectUri = RedirectUri };
if (UserId != null)
{
properties.Dictionary[XsrfKey] = UserId;
}
context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);
}
However, in the browser, nothing happens. I just get a blank page where I would expect a redirect to the Google signin page.
There are no errors reported at all.
The other funny thing is that I tried to create another MVC5 application, but I get a "Object reference not set to an instance of an object" popup in VS2013, and the resultant project is missing the Account controller that is usually there by default.
I've repaired the installation of VS2013, I have re-installed Update 1, and I've also updated all Nuget packages in the solution.
I've run out of ideas of where to go next.
Update 1
Thinking that this may be related to my PC, I've deployed the website to Azure, and the problem still persists. Does this mean it could be related to a missing assembly, and it's not being reported correctly?
I've run fusionlog, but I see no binding failures.
Spinning up a new VM with a clean install of Windows 8 and VS2013 to see if I can get a new project working there.
Update 2
Ok, just ran another round of "network" capturing, and when the user selects the external provider, it DOES post to the ExternalLogin action, but the response is a 401 Unauthorized. What could be causing this?
Ok,
I figured out what (the important part) of the issue was.
Firstly, I still don't known why when I create an MVC project I don't get a scaffold'ed AccountController class.
However, it seems my issue is that my login button was passing "google" instead of "Google" as the provider.
Seriously!? I am a little surprised that casing would matter with the name of the provider, but there you go.
This is not the answer to your question but it respond a very similar problem
If you had Owin 2.0 and you migrate to 2.1
The _ExternalLoginsListPartial need to change from this:
<button type="submit" class="btn btn-default" id="#p.AuthenticationType" name="Partner" value="#p.AuthenticationType" title="Log in using your #p.Caption account">#p.AuthenticationType</button>
to this
<button type="submit" class="btn btn-default" id="#p.AuthenticationType" name="provider" value="#p.AuthenticationType" title="Log in using your #p.Caption account">#p.AuthenticationType</button>
The only thing that change is the name of the button but that could break your head like mine and cost me 2 days of work to find the problem.
Maybe this is explained in the new Owin version, if not must be something to specify in capitals.
I've just ran into the same issue with my ASP.Net WebAPI server. I was passing the correct AuthenticationType into the challenge method but still getting a blank page.
Turns out the issue was the order I added the OAuth providers into the OWIN pipeline at startup.
Roughly my working order:
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
var authServerOptions = new OAuthAuthorizationServerOptions
{
...
};
// Token Generation
app.UseOAuthAuthorizationServer(authServerOptions);
app.UseOAuthBearerAuthentication(OAuthBearerOptions);
// Configure Google External Login
GoogleAuthOptions = new GoogleOAuth2AuthenticationOptions()
{
ClientId = xxxx,
ClientSecret = xxxx,
Provider = new GoogleAuthProvider()
};
app.UseGoogleAuthentication(GoogleAuthOptions);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
Previously I was adding the UseCors + UseWebApi methods before UseGoogleAuthentication method.
I found this post to be useful too:
http://coding.abel.nu/2014/06/understanding-the-owin-external-authentication-pipeline/
Related
I am currently familiarizing myself with both the MVC framework and Azure B2C logins / credentials. The goal is to implement some of the logic provided in the sample project to an existing project. Before getting into details about my troubles with my own project, I was not able to figure out the following:
The sample app provided (cf. https://github.com/Azure-Samples/active-directory-b2c-dotnet-webapp-and-webapi) contains a class AuthController.cs, which provides logic for Signing In / Out, etc. The methods in the AuthController appear to be called when using a partial view _LoginPartial, e.g.
#if (Request.IsAuthenticated)
else
{
<ul class="nav navbar-nav navbar-right">
<li>#Html.ActionLink("Sign up / Sign in", "SignUpSignIn", "Account", routeValues: null, htmlAttributes: new { id = "signUpSignInLink" })</li>
</ul>
}
The sign-in-method in the AccountController takes an argument string redirectUrl, e.g
public void SignUpSignIn(string redirectUrl)
{
redirectUrl = redirectUrl ?? "/";
// Use the default policy to process the sign up / sign in flow
HttpContext.GetOwinContext().Authentication.Challenge(new AuthenticationProperties { RedirectUri = redirectUrl });
return;
}
Now, the controller does not seem to be accessible when Debugging, thus I cannot figure out from where the parameter redirectUrl is passed. The reason behind this is that I would like to implement the SignUpSignIn method in an already existing controller class.
What is the relationship between the partial class and the controller and from where do I get this redirectUrl. I am sorry if my question seems trivial, but I am currently making a transition from classic ASP.NET to MVC.
You need to configure the main domain name where you're hosting your app as a reply URL in the AAD registration for your app and pass it as the redirect_uri when redirecting to AAD to allow the user to sign in.
AAD will only redirect the access token to URLs that are specified as Reply URLs in the app registration in AAD.
So in this case, redirectUrl has been set to "https://localhost:44316/". The controller gets the redirectUrl value from the web.config file.
It must match with the Reply URL configured in Azure AD.
How do I make a custom authentication provider like LinkedIn appear in SignInManager.GetExternalAuthenticationSchemes() from where Login.cshtml picks up by default
Background Details:
I am trying to understand asp.net core identity framework. In that quest, I created a standard .net core project
I tried out the supported Google authentication alongside reading the documentation and it all worked fine for me.
I was able to make LinkedIn authentication work for me, but couldn't understand how to make certain pieces work. To add support for LinkedIn authentication, I made the following changes
Added the below lines In Startup.Configure method
app.UseOAuthAuthentication(new OAuthOptions() {
AuthenticationScheme = "LinkedIn",
ClientId = Configuration["Authentication:LinkedIn:ClientID"],
ClientSecret = Configuration["Authentication:LinkedIn:ClientSecret"],
CallbackPath = new PathString("/signin-linkedin"),
AuthorizationEndpoint = "https://www.linkedin.com/oauth/v2/authorization",
TokenEndpoint = "https://www.linkedin.com/oauth/v2/accessToken",
UserInformationEndpoint = "https://api.linkedin.com/v1/people/~:(id,formatted-name,email-address,picture-url)",
Scope = { "r_basicprofile", "r_emailaddress" },
});
Added the required ClientId and ClientSecret to the configuration
Added the following line to the Login.cshtml
<button type="submit" class="btn btn-default" name="provider" value="LinkedIn" title="Log in using your LinkedIn account">LinkedIn</button>
All this works fine. Now my question is:
For supported authentication providers, as soon as I call, say, app.UseGoogleAuthentication in Startup.Configure, my call to SignInManager.GetExternalAuthenticationSchemes() in Login.cshtml lists Google as a provider. What do I need to do, so the call to SignInManager.GetExternalAuthenticationSchemes() will also list LinkedIn as a provider
What do I need to do, so the call to SignInManager.GetExternalAuthenticationSchemes() will also list LinkedIn as a provider
This method only lists the authentication middleware that have been assigned a "display name".
To include Linked in the providers list, set OAuthOptions.DisplayName:
app.UseOAuthAuthentication(new OAuthOptions
{
DisplayName = "LinkedIn"
// ...
});
I have managed to connect to the GoogleAPi with webforms but am having an issue with MVC.
In theStart.Auth i have put in the following code :
app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
{
ClientId = "6050764343-4ulkmfai2sp2bs.apps.googleusercontent.com",
ClientSecret = "oDBLHfuU9GTqp9Chcz",
CallbackPath = new PathString("/Account/ExternalLoginCallback")
});
getting the following error
The redirect URI in the request, https://localhost:44353/Account/ExternalLoginCallback, does not match the ones authorized for the OAuth client.
i have tried to add to add the following in Route.coinfig with same issue...
//routes.MapRoute(
//name: "signin-google",
//url: "signin-google",
//defaults: new { controller = "Account", action = "ExternalLoginCallback" });
also tried commenting out the line below ...when i added the route map.
CallbackPath = new PathString("/Account/ExternalLoginCallback")
});
Any insight will be greatly appreciated... Thank you
You Can implement Your External Login With Microsoft ASP.NET Identity Samples
And
For External Login You Just Need Add ClientId And ClientSecret. Also See This article Code! MVC 5 App with Facebook, Twitter, LinkedIn and Google OAuth2 Sign-on
i hope this helps anyone who is going round in circles because of not checking the default actionName in my case it was ... ExternalLoginCallback. once i changed that it all worked.!
I'm trying to use oauth with Google in ASP.NET MVC 5.
In Google's developer console I put for the redirect uri:
www.mydomain.com/account/externallogincallback
and thought that this will do. But it didn't.
I put:
www.mydomain.com/signin-google
and it worked!
I tried to search the string "signin-google" in my project but couldn't find it anywhere.
Can someone tell me what is going on? why is that so? thanks.
I am too lazy to write a properly formatted answer, I placed these comments in code for myself to remember how to resolve this issue. It is not really an issue, just something I never bothered to read properly :) But this is what you can do to make it work. There 2 options how you can do it. I have tried both and both options work just fine. I went with the first one for now, it really doesnt matter. Here are my comments in Startup.Auth.cs file.
// My notes to resolve Google Error: redirect_uri_mismatch error
// By default GoogleOAuth2AuthenticationOptions has CallbackPath defined as "/signin-google"
// https://msdn.microsoft.com/en-us/library/microsoft.owin.security.google.googleoauth2authenticationoptions(v=vs.113).aspx
// But the real path should be Controller/Action: for this application it is "/Account/ExternalLoginCallback"
// There are 2 ways to define it properly:
// 1) Add a new route in RouteConfig.cs that will map "/signin-google" into "/Account/ExternalLoginCallback":
// routes.MapRoute(name: "signin-google", url: "signin-google", defaults: new { controller = "Account", action = "ExternalLoginCallback" });
// Remember, in Google Developers Console you must have your "/signin-google" redirect URI, since that is what your app sends to Google
// 2) Completely overwrite built-in "/signin-google" path.
// Owerwrite CallbackPath right here by adding this line after ClientSecret:
// CallbackPath = new PathString("/Account/ExternalLoginCallback")
// Remember, in Google Developers Console you must have "/Account/ExternalLoginCallback" redirect URI, since now that is what your app sends to Google
app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
{
ClientId = "xxxxxxxxxxxxxxxxxxxx",
ClientSecret = "xxxxxxxxxxxxxxxxxxxxxxxx"
});
I am completely new to OWIN authentication, and I must be misunderstanding how everything works, but I can't find this mentioned anywhere.
All I want is to be able to use a central domain for authentication. If someone tries to access apps.domain.com when not authenticated, they will be redirected to accounts.domain.com/login so that all the authentication is separated into it's own domain and application. This was very easy with MVC 4 forms authentication where you can specify a full URL, but doesn't seem to be with OWIN.
In Startup.Auth.cs:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
LoginPath = new PathString("/account/login")
}
It's easy to specify the domain when setting the cookie with the CookieDomain option. However, when you specify the login path to redirect to, it has to be relative to the current application, so how do I go about accomplishing what was so easy in MVC 4 forms authentication?
Without getting too deep into what OWIN authentication is all about, I could not find anything addressing this after a couple hours of searching.
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
LoginPath = new PathString("/account/login"),
LogoutPath = new PathString("/account/logout"),
Provider = new CookieAuthenticationProvider
{
OnApplyRedirect = ApplyRedirect
},
});
}
private static void ApplyRedirect(CookieApplyRedirectContext context)
{
Uri absoluteUri;
if (Uri.TryCreate(context.RedirectUri, UriKind.Absolute, out absoluteUri))
{
var path = PathString.FromUriComponent(absoluteUri);
if (path == context.OwinContext.Request.PathBase + context.Options.LoginPath)
{
context.RedirectUri = "http://accounts.domain.com/login" +
new QueryString(
context.Options.ReturnUrlParameter,
context.Request.Uri.AbsoluteUri);
}
}
context.Response.Redirect(context.RedirectUri);
}
}
If apps.domain.com is the only return URL base possible, you should strongly consider replacing context.Request.Uri.AbsoluteUri with context.Request.PathBase + context.Request.Path + context.Request.QueryString and build an absolute return URL in your authentication server to protect your apps from abusive redirects.
Hope this helps ;)
EDIT: you might ask yourself why I don't directly apply the redirect using the context.RedirectUri property. In fact, ICookieAuthenticationProvider.ApplyRedirect is responsible of multiple redirects, corresponding to the log-in and log-out flows (yep, I know, it breaks the single responsibility principle...). But there's even worse: context.RedirectUri can either represent the authentication endpoint's absolute URL in the beginning of the log-in flow or the final browser's destination (ie. the real relative "return URL") when the cookie is effectively being sent back to the browser... that's why we need to make sure that context.RedirectUri is absolute and corresponds to the registered context.Options.LoginPath.
I am working through the examples for https://github.com/IdentityServer/IdentityServer3 and I have a different answer. In the example at https://www.scottbrady91.com/Identity-Server/Identity-Server-3-Standalone-Implementation-Part-2 they show an MVC app that uses a standalone IdP and cookies authentication. The example hasn't included getting 401 redirects working, but I stumbled on a way.
The basic scheme is to create an action in the AccountController for logging on.
public ActionResult SignIn() {
// set up some bookkeeping and construct the URL to the central auth service
return Redirect(authURL);
}
Now you have a local URL that can be used in the Startup
public class Startup {
public void Configuration(IAppBuilder app) {
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies",
LoginPath = new PathString("/Account/SignIn")
});
}
You also have the added benefit that you can put an action link to the SignIn on the menu bar, for people who want to log on before there is a 401. What we've done here is decoupled the decision of what to do when an unathenticated user asks for a resource from how the authentication is obtained.