SuppressDefaultHostAuthentication in WebApi.Owin also suppressing authentication outside webapi - c#

I am running into a problem with a solution where I used parts from the Visual Studio SPA template for having the Account Controller in WebApi with Oauth Authentication.
app.UseOAuthBearerTokens(OAuthOptions);
Then I in the owin webapi registration is doing
config.SuppressDefaultHostAuthentication();
but this also supresses the default cookie authentication outside the webapi environment. Is this the intention. If so, how can I set up WebApi to supress cookie authentication but its still active accross the environment for other requests?

It seems that it is a good practice, especially when you mix an OWIN-hosted app and a regular one on the same IIS dir, to setup WebApi with the app.Map.
public void Configuration(IAppBuilder app)
{
var configuration = WebApiConfiguration.HttpConfiguration;
app.Map("/api", inner =>
{
inner.UseWebApi(configuration);
});
}
I had all my controllers configured with a "api" prefix route, and I just moved that to the map function instead. Now webapi is running isolated and it works out with the rest of my application. Thanks #PinpointTownes for pointing me in this direction.

Related

.Net Core 3.1 Merging JWT and OpenIDConnect Authentication

Short version: I am having trouble in merging together the correct Authentication config in my .NET Core MVC Website to allow my users to authenticate against Azure Active Directory, but to also allow a Daemon connection (from a Console App) in, too.
Long version:
I've got a .NET Core MVC website, which authenticates against Azure Active Directory perfectly fine when using the following in the ConfigureServices method in the Startup.cs:
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddSignIn("AzureAd", Configuration, options => Configuration.Bind("AzureAd", options));
I am also trying to get my .NET Core Console App to call into the APIs (as a Daemon connection) into the above MVC website (all is configured in the App Registration section in my Microsoft Azure account). I can connect the Console App to the MVC website and it will successfully hit an Action Result in a controller but only if I am using the following in the ConfigureServices method in the Startup.cs of the website:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddProtectedWebApi("AzureAd", Configuration, options => Configuration.Bind("AzureAD", options));
BASICALLY, if I only use the OpenIdConnect option, my web users can access the website but my console app is denied. If I only use the JwtBearer option, then my Console App can connect, but my web users are denied.
I have Google-Bing'd all day and I'm struggling to get a mash-up of these two configurations to work without knocking the other out.
I have tried to use the .AddJwtBearer() method, but am completely confused by it:
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddSignIn("AzureAd", Configuration, options => Configuration.Bind("AzureAd", options))
.AddJwtBearer(options => Configuration.Bind("AzureAD", options));
How do these work together, such that both can be in place and my web app works through a browser, and the Console App (Daemon) works too? Can I bind both to my appsettings.json file??
Incidentally, the appsettings.json file looks like this:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "zzzzzzzzzzzzzz.onmicrosoft.com",
"TenantId": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
"ClientId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"CallbackPath": "/signin-oidc",
"SignedOutCallbackPath ": "/signout-callback-oidc",
"ClientSecret": "myAzureClientSecret"
}
}
UPDATE 2020-06-15:
Having working on/off of this for AGES, I've found a suitable resolution that works, hence my awarding the bounty points to #michael-shterenberg. ALSO, I now know that I have a great deal to learn from #gary-archer and his impressive blog site. I just happened to get success from Michael's input.
Here's the mods to the Startup.cs file, within the ASP.NET Core MVC Web App in the diagram above:
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddSignIn("AzureAd", Configuration, options =>
Configuration.Bind("AzureAd", options))
.AddJwtBearer(o =>
{
o.Authority = "https://login.microsoftonline.com/common";
o.TokenValidationParameters.ValidateAudience = false;
o.TokenValidationParameters.ValidateIssuer = false;
});
services.AddAuthorization(options =>
{
options.AddPolicy("UserAndApp", builder =>
{
builder.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme);
builder.AuthenticationSchemes.Add(OpenIdConnectDefaults.AuthenticationScheme);
builder.RequireAuthenticatedUser();
});
});
...coupled with the use of the following attribute on the Controller that I'm trying to call from the Daemon app.
[Authorize("UserAndApp")]
My users can still log into the website using the Azure Active Directory processes and now my automated processes can log in, too.
In case anyone is struggling to understand how the Azure App Registration side of all of this works, try this really explanatory blog post:
Secure a .NET Core API using Bearer Authentication
(I wish that I had seen that earlier, when I was trying to get my head around how the Azure App Registration process works!)
Here is the solution that worked for me (Tested on ASP .NET Core 2.1 and 3.1)
Don't set a default authentication scheme since you have 2 types (Cookies and JWT). i.e. your call to AddAuthentication should be without parameters:
services.AddAuthentication()
.AddAzureAD(options => Configuration.Bind("AzureAd", options))
.AddJwtBearer(o=> {
o.Authority = "https://login.microsoftonline.com/common";
o.TokenValidationParameters.ValidateAudience = false;
o.TokenValidationParameters.ValidateIssuer = false;
});
Note that I explicitly didn't bind your AD configuration because /common is needed to be applied to the authority (or the tenant id)
Also I set validation for audience and issuer to false so that any AAD token will work for testing. You should obviously set the correct audience/issuer
I used AddAzureAd and not AddSignIn (is that a custom external library you are using?)
Create a policy that accepts both authentication schemes:
services.AddAuthorization(options =>
{
options.AddPolicy("UserAndApp", builer =>
{
builer.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme);
builer.AuthenticationSchemes.Add(AzureADDefaults.AuthenticationScheme);
builer.RequireAuthenticatedUser();
});
});
Replace this with your existing authorization setup
Use the new policy name in your controller:
[Authorize("UserAndApp")]
public class HomeController : Controller
Some explanation on the mechanics:
You don't want to setup automatic authentication scheme since this will be the default schema run in the authorization middleware, while you have 2 different types
The policy will try run both authentication handlers, if one of them succeeds then authentication succeeded
Note: if you send a request with an invalid Bearer token, both authetnication handlers will fail, in this case the AzureADDefaults will "win" since it actually implement a challenge method and will redirect you (status code 302), so make sure to handle this in your app
It feels like the architecture is not quite right, and you need to separate the 2 roles performed by your Web Back End:
CURRENT WEB ONLY ARCHITECTURE
You have a Web UI front end that uses auth cookies
You have a Web Back End that requires cookies for view requests
You have a Web Back End that requires cookies for API requests
You have a Console Client that cannot use cookies so cannot call API entry points
MULTI CLIENT ARCHITECTURE
You'll need to update the web back end to include API entry points that are secured by OAuth 2.0 access tokens and not by cookies. The console app will then be able to call your web back end.
.NET CORE SUB PATHS
Introduce an additional /api subpath in your web back end. The UseWhen feature will allow you to do this without impacting other web back end behaviour:
/*
* Apply API behaviour to only subpaths, without impacting the rest of the app
*/
app.UseWhen(
ctx => ctx.Request.Path.StartsWithSegments(new PathString("/api")),
api => {
api.useAuthentication();
api.useJwtBearer();
});
EXAMPLE .NET CORE API
For an example that uses subpaths, see my Sample .Net Core API. The startup class is where ASP.Net middleware is wired with different authenticaiton handling for different subpaths.
FUTURE POSSIBILITIES
Once you have the above logical separation you could potentially evolve it further in future, eg to a completely cookieless model:
Develop APIs as completely independent components based only on tokens
Update the Web UI to an SPA that uses client side security libraries
My blog at https://authguidance.com follows this approach, and my sample APIs all support any type of client.

Add token authentication for webApi controller to existing asp.net MVC 5 application

I currently have a Web API controller added to an existing MVC 5 project (not using .net core) and I was able to successfully create and get data from the controller that I have set up. The purpose of the API is to pass data between it and a mobile application that uses the same data source that the MVC project uses (I will also be calling existing methods in the project from the API so I would prefer the API exist in the MVC project). I am now looking for a way to add token authentication to the API, as I only want logged in users in the mobile application to be allowed to access the API. How can I achieve this?
The simplest solution should be to use the Token Validation Middleware from the IdentityServer 3 suite.Just add the nuget package and configure your application following the doc:
public class Startup
{
public void Configuration(IAppBuilder app)
{
// turn off any default mapping on the JWT handler
JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();
app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
{
Authority = "https://localhost:44333/core",
RequiredScopes = new[] { "api1" }
});
app.UseWebApi(WebApiConfig.Register());
}
}
It's ok to set app.UseIdentityServerBearerTokenAuthentication() only prior to app.UseCookieAuthentication() and app.UseOpenIdConnectAuthentication() and call GlobalConfiguration.Configure(WebApiConfig.Register) in Global.asaxSuch approach allows to combine token and cookie-based auth in one MVC application.The only problem for today is that IdentityServer 3 family tools are frozen and support System.IdentityModel 4 and OWIN 3 only, so
update:
The preferred solution for ASP.NET 4.6+ becomes IdentityServer3.Contrib.AccessTokenValidation -- a fork, refactored according to the recent framework changes.

Stateless authentication with NancyFx, OWIN and JWT

I have a OWIN self-hosted application which has a front-end where users can sign up. Nancyfx does the logic for routing and Models, and in the documentation I saw that Nancyfx comes with 3 types of authentication.
Forms (Nancy.Authentication.Forms)
Basic (Nancy.Authentication.Basic)
Stateless (Nancy.Authentication.Stateless)
I've settled on the Stateless Authentication, and following this example I tried to set up a basic form of authentication.
I wanted to expand further on this, using JWT to have some basic info handy and as a form of basic authentication (e.g. client has token so he's verified.), but this is where I run into a few problems.
The way I authenticate Home -> login -> redirect upon success causes my Response.Header.Authorization to be cleared, not allowing me to catch the token in my custom Bootstrapper.
Code:
protected override void RequestStartup(TinyIoCContainer requestContainer, IPipelines pipelines, NancyContext context)
{
AllowAccessToConsumingSite(pipelines);
StatelessAuthentication.Enable(pipelines, requestContainer.Resolve<IStatelessAuthConfigurationFactory>().Config());
}
//Returns ClaimsPrincipal or Null;
public StatelessAuthenticationConfiguration Config()
{
if(_stat == null)
{
_stat = new StatelessAuthenticationConfiguration(VerifyToken);
}
return _stat;
}
Since my authorization header disappears every request, I would need to persist the JWT. I figure it's possible using OWIN environment or Nancy context, but would this be advisable + what would the effect be for a multi-user environment regarding security.
OWIN has it's own authentication Manager that I could use, I've experimented with it, but it tends to provide a cookie upon successful sign in, which it doesn't seem to revoke on Logout. I just ran into a few issues overall with it, so I settled on NancyFx authentication. (not really a problem as a more general remark I suppose)
Thanks in advance for any help!
Regarding (1), if you roll your own redirection after a successful login, consider setting the Authorization header during the redirect, e.g.
return Response.AsRedirect("/").WithHeader("Authorization", token);
It's actually the responsibility of the client to hold the valid JWT token after authentication. Returning it as a cookie (and deleting it upon logout) could make things easier in terms of client-side implementation and avoid the token persistence issue.
Regarding (2), not really, it's not necessary. JWT tokens are self-contained, and that's why they're useful in stateless auth scenarios.

ASP.NET Core with optional authentication/authorization

I want to build an ASP.NET Core based WebApi for accessing data from a database. This WebApi could be used in two ways, either as a public WebApi which would need authentication or as a private backend service for a web application. In the latter case there would be no need for authentication since only authenticated users can access the web application and both web application and WebApi will run on the same computer, the WebApi will be hidden to the outside.
Since we need authentication for the first scenario, I will have all public APIs tagged with the Authorize attribute. But for the private scenario I would like to bypass any authentication.
Is there any way I could make authentication optional depending on some flag in the configuration?
Update
speaking of two usage scenarios I mean two completely separate installations! Each one has its own configuration file. The decision whether authentication is needed is to made per installation not per request in a single installation! My goal is to have just one code base and a switch in the configuration.
If you bypass authentication, how do you distinguish internal or public requests for api? This causes security bug. So you shouldn't bypass authentication.
If you use openidconnect authentication in mvc application then you can set SaveTokens=true. It enables you to store access token in cookie. When you call api in mvc action you can send this access_token to api.
Another way using two different authentication middleware, one for internal another for public access(This is hard to implement).
I would go with first approach.
Update
To achieve your goal, a tricky way is coming to my mind but i am not sure it is good way:
Create a filter provider:
public class EncFilterProvider : IFilterProvider
{
public int Order
{
get
{
return -1500;
}
}
public void OnProvidersExecuted(FilterProviderContext context)
{
}
public void OnProvidersExecuting(FilterProviderContext context)
{
// remove authorize filters
var authFilters = context.Results.Where(x =>
x.Descriptor.Filter.GetType() == typeof(AuthorizeFilter)).ToList();
foreach(var f in authFilters)
context.Results.Remove(f);
}
}
Then register it conditionally based on config value
public void ConfigureServices(IServiceCollection services)
{
if(config["servermode"] = "internal")
{
services.AddScoped<IFilterProvider, EncFilterProvider>();
}
}
I would recommend to authenticate both applications: web application and the Web API one. You will have everything secured.
For skipping an authentication that is not a good idea. Simply create an user for your web application (in the Web API application) which will be used to authenticate when getting data from the Web API.

Using OAuth to connect to a Windows Azure Active Directory

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.

Categories