I need to access some Google APIs (via Google.Apis.* NuGet Packages). Therefore I need to use the Google.Apis.Auth.AspNetCore package as described in the
official documentation:
services
.AddAuthentication(o =>
{
o.DefaultChallengeScheme = GoogleOpenIdConnectDefaults.AuthenticationScheme;
o.DefaultForbidScheme = GoogleOpenIdConnectDefaults.AuthenticationScheme;
o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddGoogleOpenIdConnect(options =>
{
options.ClientId = googleClientId;
options.ClientSecret = googleClientSecret;
});
On the other hand, I use classical ASP.NET Core Identity, especially the Google external login setup
using the
Microsoft.AspNetCore.Authentication.Google NuGet package which is initialized like this:
services
.AddAuthentication()
.AddGoogle(options =>
{
options.ClientId = googleClientId;
options.ClientSecret = googleClientSecret;
});
Is there a way to share the OAuth configurations, logins, ...? 🤔 Both packages use their own OAuth intialization code... 💠Will I face problems calling both AddGoogle() and AddGoogleOpenIdConnect()?
Background info
Authorization is OAuth2. You would use it for example to request access to a users google drive account. Once you have been granted access you would be given a refresh token and you would be able to access the users data when ever you need.
Open id connect its authentication or login. It tells you that a user is in fact logged in it doesn't give you access to more then the users profile information by default.
Google.Apis.Auth.AspNetCore
Strictly speaking the Google APIs library normally only gave you access to authorization. However Google.Apis.Auth.AspNetCore does add an open id connect component to to the authentication in the form of AddGoogleOpenIdConnect which will give you both authentication and authorization at the same time.
Microsoft.AspNetCore.Authentication.Google
Is as its states Authentication or login. The user is logging in and authenticating that they are currently accessing your application.
recap
Microsoft.AspNetCore.Authentication.Google only gives you authentication or login, while Google.Apis.Auth.AspNetCore will potentially give you login and authorization.
Adding both
TBH I question why you would add both. Technically if you did and they didn't bash heads with each other which they might. You may end up with a double login. As these two libraries will both be trying to Authenticate the user. You will need two access tokens one for each library. I'm not sure if they set different cookies or not if they set the same cookie then they will reset each other cookies causing the user to need to login or authorize the application again to reset the cookie for each library you are trying to use.
Not to mention what adding [Authorize] attribute to a method is going to do how will it know which one to pick if your adding to authorization forms
Related
I'm new to asp core, I have implement the following to login AD identity,
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
and also the following to login with user name / password and add cookie,
builder.Services.AddAuthentication("Auth1").AddCookie("Auth1", options => { options.Cookie.Name = "Auth1"; });
but how can I add both authentication to allow either case to login?
I have both tested working properly but cannot add both to builder.services.
Please recommend web page reference or approach to implement this.
So I'm trying to set up PayPal sign-in within my .net core application. I'm using this 3rd party library to do so: https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers
I'm building my application upon Umbraco CMS, and within the appropriate section I use the following:
builder.AddMemberExternalLogins(logins =>
{
logins.AddMemberLogin(
memberAuthenticationBuilder =>
{
memberAuthenticationBuilder.AddPaypal(
memberAuthenticationBuilder.SchemeForMembers(PayPalMemberExternalLoginProviderOptions.SchemeName),
options =>
{
options.ClientId = clientId;
options.ClientSecret = clientSecret;
});
});
});
Out of the box, this does not work. From reading around it seems that it seems the authorization endpoints are using the live values, and these are not appropriate for testing with Paypal's sandbox endpoints.
After reading the following thread: https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers/issues/198 I can see that this user had to update the endpoints manually to use different values:
.AddPaypal(options =>
{
options.ClientId = Startup.Configuration["Authentication:Paypal:ClientId"];
options.ClientSecret = Startup.Configuration["Authentication:Paypal:ClientSecret"];
options.AuthorizationEndpoint = "https://www.sandbox.paypal.com/webapps/auth/protocol/openidconnect/v1/authorize";
options.TokenEndpoint = "https://api.sandbox.paypal.com/v1/identity/openidconnect/tokenservice";
options.UserInformationEndpoint = "https://api.sandbox.paypal.com/v1/identity/openidconnect/userinfo?schema=openid";
})
Now once updating these values, the authorization seems to work. But I've found it to be very unreliable. On my personal dev machine it seems to allow me to authorize, but when testing with another colleague, he finds he is constantly logged out and sometimes it doesn't authorize at all.
When I look at the previous thread I can see that this was written in 2017, and I'm wondering if the endpoints have been updated or the process has been changed entirely by Paypal, but I can't find any documentation on this.
Basically I'm looking for the simplest way to integrate Paypal sign-in on my application. When I read Paypal's documentation (https://developer.paypal.com/docs/log-in-with-paypal/integrate/) I only see mention of refreshing the token, I don't see anything about an authorization endpoint or user information endpoint.
I'm getting quite confused and I'm wondering if anyone has successfully managed to set up a Paypal sign-in with a .net core application in 2022 and whether they have any sample code.
Any pointers would be greatly appreciated. Thanks.
That does seem like an old integration. I would advise following https://developer.paypal.com/docs/log-in-with-paypal/integrate/ from scratch, which can be implemented in any language for the eventual server-side calls. The initial client-side authorization is done in either the JS popup or using a redirect (JS is better)
After exchanging the resulting authorization_code for a refresh token, that token can then be used to obtain information about the user's account (or do API operations involving it), according to the scopes that were authorized.
We've been leveraging Cookie authentication within our .NET Core 2.2 application & logging users in after verifying their identity via Microsoft external 3rd party provider. Just recently, we've observed an error in this workflow which states:
Microsoft.AspNetCore.Authentication.MicrosoftAccount.MicrosoftAccountHandler:Information: Error from RemoteAuthentication: Correlation failed.."
We've narrowed it down to the scenario where if a user is already logged in to their Microsoft account (only one account logged in/active)... and if they then log in to our website they are automatically signed in without having to select their account name or any other interaction. What's more, if the user DOES click on their account name, this fires off another sign in request & I believe is resulting in the "Correlation failed.." error due to the request/response cookies being in conflict.
I am able to reproduce the issue from localhost, though our actual hosting provider is within Azure (App Services).
I've already explored some of the solutions/approaches mentioned within the following Microsoft docs which mention configuration for load balancers and proxy servers (Forwarding Headers)... as well as enforcing HTTPS in ASP.NET Core:
https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-2.1
https://learn.microsoft.com/en-us/aspnet/core/security/enforcing-ssl?view=aspnetcore-2.1&tabs=visual-studio
These do not appear to address the root of the issue which I understand to be the automatic sign-on/selection of the user account when the security Challenge is made to the Microsoft provider.
Here is a snippet from our Startup.cs service configuration for the 3rd party authentication config.
// Authentication is added via Cookie
services.ConfigureApplicationCookie(options => options.LoginPath = "/Login");
services.AddAuthentication(opts =>
{
opts.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
opts.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(opts =>
{
opts.Cookie.SecurePolicy = CookieSecurePolicy.Always;
opts.LoginPath = "/auth/login";
opts.LogoutPath = "/auth/logout";
opts.ClaimsIssuer = "<ISSUER_HERE>"; // *** redacted for privacy
})
.AddMicrosoftAccount(options =>
{
options.ClientId = Configuration["Authentication:ApplicationId"];
options.ClientSecret = Configuration["Authentication:Password"];
options.Events.OnRemoteFailure = ctx =>
{
// React to the error here. See the notes below.
ctx.Response.Redirect("/error?FailureMessage=" + UrlEncoder.Default.Encode(ctx.Failure.Message));
ctx.HandleResponse();
return Task.FromResult(0);
};
});
Ideally, the "automatic sign-on" behavior is prevented so the user must select their account from the Microsoft account selection prompt (even if they've previously signed in).
For now, we're redirecting the user to an error page, where we can clear all cookies and have the user re-attempt the login. This poses a problem if they continually select their user account during the login process & both requests are conflicting.
Any insight would be greatly appreciated!
Alrighty then, I got it.
It seems a bit hacky, but hey, it works.
.AddMicrosoftAccount(options =>
{
// Your configuration here
options.Events.OnRedirectToAuthorizationEndpoint = context =>
{
context.HttpContext.Response.Redirect(context.RedirectUri + "&prompt=select_account");
return Task.FromResult(0);
};
})
It's easy to create an ASP.NET MVC application that authenticates based on windows domain user. It's also easy to create one that uses individual accounts stored using Entity Framework. In fact, there are project templates for both.
But I want to utilize BOTH kinds of authentication in the same application. I tried to combine the code from both project templates. I have a problem in Startup.Auth.cs.
// from "Individual Accounts" template
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
The existence of cookie authentication owin middleware seems to cause domain identities to become un-authenticated. If I take this line out, the domain authentication works. But without it, I can't seem to support individual user accounts.
I've downloaded the katana project source code and examined CookieAuthenticationHandler.cs, but I don't quite understand how it works in the context of an OWIN pipeline.
How can I use the ASP.net identity framework to allow my application to authenticate users from the windows domain OR an application-specific user store?
The simplest approach is to have 2 different presentation Projects only for Authentication/Authorization.
This has the advantage of leaning on existing framework and standard configuration.
From there, you decide to either
create an AD user for every internet user, or
create a DB/Internet user for every AD user.
Creating an Identity user for each AD user is easier to implement further. Then the same cookies and filters can exist in the entire app.
In that case you can either
use subdomain(s) for your app
AD Authentiction Project can have the singular purpose of Authentication / Authorization, then the Web App can represent the rest of your app.
Alternatively, If you want a truly Unified Solution, use MohammadYounes/Owin-MixedAuth
MohammadYounes/Owin-MixedAuth
Install-Package OWIN-MixedAuth
In Web.config
<location path="MixedAuth">
<system.webServer>
<security>
<authentication>
<windowsAuthentication enabled="true" />
</authentication>
</security>
</system.webServer>
</location>
In in Startup.Auth.cs
app.UseMixedAuth(cookieOptions);
:
:
How it works:
The handler uses ApplyResponseChallengeAsync to confirm the request is a 401 challenge. If so, it redirects to the callback path to request authentication from IIS which is configured to query the AD.
AuthenticationResponseChallenge challenge = Helper.LookupChallenge(
Options.AuthenticationType, Options.AuthenticationMode);
A 401 challenge is caused by an unauthorized users attempting to use a resource that requires Authentication
The handler uses InvokeAsync to check if a request is coming from a callback path (IIS) and then calls AuthenticateCoreAsync
protected async override System.Threading.Tasks.Task<AuthenticationTicket>
AuthenticateCoreAsync()
{
AuthenticationProperties properties = UnpackStateParameter(Request.Query);
if (properties != null)
{
var logonUserIdentity = Options.Provider.GetLogonUserIdentity(Context);
if (logonUserIdentity.AuthenticationType != Options.CookieOptions.AuthenticationType
&& logonUserIdentity.IsAuthenticated)
{
AddCookieBackIfExists();
ClaimsIdentity claimsIdentity = new ClaimsIdentity(
logonUserIdentity.Claims, Options.SignInAsAuthenticationType);
// ExternalLoginInfo GetExternalLoginInfo(AuthenticateResult result)
claimsIdentity.AddClaim(new Claim(ClaimTypes.NameIdentifier,
logonUserIdentity.User.Value, null, Options.AuthenticationType));
//could grab email from AD and add it to the claims list.
var ticket = new AuthenticationTicket(claimsIdentity, properties);
var context = new MixedAuthAuthenticatedContext(
Context,
claimsIdentity,
properties,
Options.AccessTokenFormat.Protect(ticket));
await Options.Provider.Authenticated(context);
return ticket;
}
}
return new AuthenticationTicket(null, properties);
}
AuthenticateCoreAsync uses AddCookieBackIfExists to read the claims cookie created by AD and creates it's own Claims based.
AD users are provided a Claims based Cookie identical to Web Users. AD is now like any other 3rd party authenticator (Google, FB, LinkedIN)
It's for this reason that I haven't been able to use pre-baked solutions for authentication. In our project, the passing years (and agile approach) have left us with 4 different ways to authenticate which is annoying, but we support all legacy versions of apps in the field so we have to preserve it all (at least for now).
I ended up creating a factory that figures out the authentication mechanism (through any of several means such as token format, presence of some other thing) and then returns a wrapper that carries the logic for validating that authentication method and setting the principal.
This gets kicked off in a custom HTTP module so that the principal is built and authenticated before the request gets to the controller. In your case, windows Auth would be the final fallback, I think. In our Web API application, we took the same approach but through a delegating handler instead of HTTP module. It's a type of local token federation, you could say. The current implementation allows us to add or modify any validation procedure, or add any other token format; in the end, the user ends up with a proper identity or gets denied. Only took a few days to implement.
It seems to me the best answer to this question is to use an authentication and authorization framework. There are plenty to choose from (both commercial and free). You could, of course, write your own but I would discourage it. Lots of very smart people get this wrong.
I would take a look at IdentityServer3. It's certainly not the only solution but its a pretty good authentication and authorization framework. It's open source and pretty easy to get up and running in a hurry. Your use case is a common one and you will find some very useful information at the link above. Clean separation between authorization and authentication, social authentication options, easy to work with json web tokens that encapsulate user claims, etc.
How it can help you
IdentityServer3 allows you to configure Identity Providers to handle authentication and there are plenty of extension points that will allow you to implement a chain of responsibility that can handle both of your scenarios. From the docs:
IdentityServer supports authentication using external identity providers. The external authentication mechanism must be encapsulated in a Katana authentication middleware.
Katana itself ships with middleware for Google, Facebook, Twitter, Microsoft Accounts, WS-Federation and OpenID Connect - but there are also community developed middlewares (including Yahoo, LinkedIn, and SAML2p).
To configure the middleware for the external providers, add a method to your project that accepts an IAppBuilder and a string as parameters.
IdentityServer3 supports AD as an identity providor via a browser login window and will support a more programmatic implementation via a custom grant. You can also take a look here for some more information on IdentityServer3 and AD authentication.
It will support windows authentication as well and you can take a look at here for information and examples on implementing that.
There is a pretty good getting started example here as well.
With the right configuration IdentityServer3 can handle your requirements. You will need to implement your own authentication providers and plug them into the framework but there isn't much more to it than that. As for authorization goes, there are plenty of options there as well.
In the scaffolding for an ASP.NET MVC project, the StartUp.Auth.cs file currently contains this code:
public partial class Startup
{
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
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: "0000000000000000",
clientSecret: "xxxx-xxxxxxxxxxxxxxxxxxx-xxxxxxx");
//app.UseTwitterAuthentication(
// consumerKey: "",
// consumerSecret: "");
//app.UseFacebookAuthentication(
// appId: "",
// appSecret: "");
//app.UseGoogleAuthentication();
}
}
Uncommenting the app.UseXxxAuthentication() lines and adding in your provider's key and secret gives you the ability to use the respective providers to perform OAuth logins. Under the covers, these methods use classes derived from the Owin class AuthenticationMiddleware.
I have looked on the web, but I cannot find a custom implementation of AuthenticationMiddleware that links directly to a Windows Azure Active Directory instance. Are there any such implementations?
Is this the right way to use OAuth to connect to my Windows Azure Active Directory instance?
You should be able to go to your Package Manager, and NuGet import the Katana Owin implementations for Windows Azure AD, which will be listed as Microsoft.Owin.Security.ActiveDirectory This is the middleware that enables an application to use Microsoft's technology for authentication. The current version as of this post is 2.0.2
Once you have that, you should be able to leverage the middleware for AD and ADFS 2.1 oAuth tokens like so:
WindowsAzureActiveDirectoryBearerAuthenticationOptions myoptions = new WindowsAzureActiveDirectoryBearerAuthenticationOptions();
myoptions.Audience = "https://login.windows.net/myendpoint";
myoptions.Tenant = "mydirectory.onmicrosoft.com";
myoptions.AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Passive;
app.UseWindowsAzureActiveDirectoryBearerAuthentication(myoptions);
That should give you the ability to have the Owin middleware use Windows Azure AD Bearer Authentication in this scenario.
Happy coding!
I don't believe you can use WAAD in this way. Microsoft Account is for what used to be Windows Live ID (More information here), and this is different from WAAD. And the OAuth implementation in WAAD is not complete yet and in preview (more details here). The best way to use WAAD today is via WS-Federation / WIF.
The pain point in VS 2013 is that you can't do it easily manually, nor you can change the selected authentication once you created the project.
The easiest way to get the required configuration is to go and create new web app, and change the authentication. Chose Change Authentication at the very first step of the wizard (where you select the type of App - MVC, WebAPI, etc.). Then choose Organizational Account. It has only one option - Cloud single organization - enter your tenant domain name (may be the xxxx.onmicrosoft.com). And chose access level (Single Sign On, SSO + read directory data, SSO + read + write directory data). Next you will be asked to sign in with account which is Global Administrator in this Active Directory. The wizard will create necessary web.confg changes and Identity configuration.
There still no support in OWIN for WAAD, and it will create a new IdentityConfig.cs instead Startup.Auth.cs file. You can then copy generated files and web.config changes into your project. You can still combine WAAD with other providers and OWIN, but this still requires more advanced skills.
It is a little more complicated that it should be. But things may change for good in the future.
There is a new Owin middleware that adds Ws Federation authentication to your site with a few simple lines of code much like the individual account examples in the new MVC project template. It's currently in alpha but here is a link to an article explaining how to create your app in Windows Azure Active Directory and configure the OWIN middleware.
However this uses cookie authentication rather than OAuth tokens but this should be sufficient for a pure ASP MVC site.