Cookie Authentication with ASP.NET 5 MVC 6 Web API - authentication

I totally understand if someone finds that my question is very basic or might not make a lot of sense all the way.
I am new to this and I am trying to use the latest .NET Framework 5 with MVC 6 in order to build a Web Api that could be used from an Angular JS client-side. This will allow me to create a website for it, as well as a mobile application by wrapping it with Phonegap. So please bear with me a bit.
What I am trying to achieve for the moment is to have a Web API controller that receives a login request and returns a result to the client based on Cookie Authentication (later the client should store this cookie and use it for communications with the server)
I added the following in the project.json
In the Startup.cs, I added under ConfigureServices:
// Add entity framework support
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<ApplicationDbContext>(options =>
{
options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]);
});
// add ASP.NET Identity
services.AddIdentity<ApplicationUser, IdentityRole>(options => {
options.Password.RequireDigit = false;
options.Password.RequireLowercase = false;
options.Password.RequireUppercase = false;
options.Password.RequireNonLetterOrDigit = false;
options.Password.RequiredLength = 6;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
In the Startup.cs, under Configure:
// Using the identity that technically should be calling the UseCookieAuthentication
app.UseIdentity();
Now, in the Controller method to login, I am able to find the user using its email address and the UserManager:
// Verify that the model is valid according to the validation rules in the model itself.
// If it isn't valid, return a 400 Bad Request with some JSON reviewing the errors
if (!ModelState.IsValid)
{
return HttpBadRequest(ModelState);
}
// Find the user in our database. If the user does not exist, then return a 400 Bad Request with a general error.
var user = await userManager.FindByEmailAsync(model.Email);
if (user == null)
{
ModelState.AddModelError("", INVALID_LOGIN_MESSAGE);
return HttpBadRequest(ModelState);
}
// If the user has not confirmed his/her email address, then return a 400 Bad Request with a request to activate the account.
if (!user.EmailConfirmed)
{
ModelState.AddModelError("Email", "Account not activated");
return HttpBadRequest(ModelState);
}
// Authenticate the user with the Sign-In Manager
var result = await signInManager.PasswordSignInAsync(user.UserName, model.Password, model.RememberMe, lockoutOnFailure: false);
// If the authentication failed, add the same error that we add when we can't find the user
// (so you can't tell the difference between a bad username and a bad password) and return a 400 Bad Request
if (!result.Succeeded)
{
ModelState.AddModelError("", INVALID_LOGIN_MESSAGE);
return new BadRequestObjectResult(ModelState);
}
return Ok();
The problem is happening at the line:
// Authenticate the user with the Sign-In Manager
var result = await signInManager.PasswordSignInAsync(user.UserName, model.Password, model.RememberMe, lockoutOnFailure: false);
it is throwing the following error:
Error: No authentication handler is configured to handle the scheme:
Microsoft.AspNet.Identity.Application
I am currently blocked and I searched googled for almost every possible token I could think of and tried multiple solution still in no vain. Any help is highly appreciated.
Regards,

Ok I finally figured it out after writing this whole question and I wanted to share the answer to avoid the hussle for someone else if they commit the same mistake I did!
The problem was that in the Configure in Startup.cs, I called "app.UseIdentity()" after calling "app.UseMVC()". The order should have been inversed. I donno if this is common knowledge or I should have read about it somewhere.

Related

ConfidentialClientApplication Caching - GetAccountAsync

the
Lately I joined a project that is using Azure AD Open ID connect authentication code to authenticate with the ASP.Net Core web application.
When I am trying to run it locally I am facing issues with retrieving info with the GetAccountAsync method (Return null). From what I read, I think the code is missing a caching helper to cache the user/application tokens.
public async Task<string> GetUserAccessTokenAsync(string userId)
{
var account = await _app.GetAccountAsync(userId);
try
{
var result = await _app.AcquireTokenSilent(_scopes, account).ExecuteAsync();
return result.AccessToken;
}
// Unable to retrieve the access token silently.
catch (Exception)
{
throw new ServiceException(new Error
{
Code = GraphErrorCode.AuthenticationFailure.ToString(),
Message = "Caller needs to authenticate. Unable to retrieve the access token silently."
});
}
}
If anyone has any idea what I could do to fix this issue Ill be happy to know :)
Thank you!

IdentityServer 4 Authentication Event in Client

I have an IdentityServer 4 server set up as a stand-alone app, using net core 3.1, Entity Framework core against MySql and Net Core Identity as a user store. Separately I have a Razor Pages client app, which authenticates against the Identity Server, with user logon taking place on the server. All this is working fine.
I now wish to be able to write a log entry on the client for any new user authentication or failed logon. I assume there must be events raised somewhere. How do I go about this, please?
I had the same requirement, to store for example authentication failure in audit log - if someone tried to access api with invalid token.
What I found is that IdentityServerAuthenticationOptions has JwtBearerEvents property which can be used to be notified about such events.
In my case it worked this way:
.AddAuthentication(AUTH_SCHEME).AddIdentityServerAuthentication(AUTH_SCHEME, options => {
options.ApiName = config.ApiName;
options.Authority = config.Address;
options.JwtBearerEvents = new JwtBearerEvents
{
OnAuthenticationFailed = c =>
{
// Log can bo done here
return Task.CompletedTask;
},
OnTokenValidated = c =>
{
// Log can bo done here
return Task.CompletedTask;
},
OnChallenge = c =>
{
// Log can bo done here
return Task.CompletedTask;
},
OnForbidden = c =>
{
// Log can bo done here
return Task.CompletedTask;
}
};
options.SupportedTokens = SupportedTokens.Jwt;});
I was afraid that it will override normal IS behavior, but everything seems to work as it used to.
You have access to proper contexts there, for example in JwtBearerChallengeContext you can read Error or ErrorDescription strings or even whole HttpContext.

Protecting static files with Authorization Middleware using IdentityServer4

I have a IS4 set up and most of the clients that use it get their pictures from a simple ASP.NET Core API. There is one method for adding pictures that go to wwwroot. I noticed that, while unauthorized users can't add new pictures, anyone can access the pictures if they know the URL. After a quick search, i found out that i need a middleware to protect static files, so i shamelessly used sir Alan's code from here. After modifying it for ASP.NET Core (unsure if i did it correctly), i couldn't get authorized from any of the clients (I would get a 401 response, so at least that works correctly).
Here are the services added:
services.AddAuthentication(
IdentityServerAuthenticationDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
options.Authority = "http://some.url";
options.ApiName = "SomeAPI";
options.RequireHttpsMetadata = false;
});
services.AddAuthorization(options =>
{
options.AddPolicy("Authenticated", policy => policy.RequireAuthenticatedUser());
});
And the Invoke method from ProtectFolder, that i modifyied:
public async Task Invoke(HttpContext httpContext,
IAuthorizationService authorizationService,
IAuthenticationService authenticationService)
{
if (httpContext.Request.Path.StartsWithSegments(_path))
{
var authenticated = await authenticationService.AuthenticateAsync(httpContext,
IdentityServerAuthenticationDefaults.AuthenticationScheme);
var authorized = await authorizationService.AuthorizeAsync(httpContext.User, null, _policyName);
if (!authorized.Succeeded)
{
await authenticationService.ChallengeAsync(httpContext,
IdentityServerAuthenticationDefaults.AuthenticationScheme, authenticated.Properties);
return;
}
}
await _next(httpContext);
}
So i managed to protect the files, but now I can't access them either. Since I'm using IS4 I'm pretty sure I need to use the token for authorization, but I'm unsure how.
I checked this answer and put UseAuthentication above UseProtectFolder and UseStaticFiles, but I still get a 401 response. I also checked this answer, but I'm unsure if it will help, since I'm not using the controller to get the files.

Use ASP.Net Core 2 Identity with Azure Ad single tenant authentication

I would like to get help from community for one problem that I don't understand.
I create asp.net core 2 web application and I would like to configure the app to be able to login from the app via aspnetuser table or by using O365 Company account.
Then I followed multiple techniques described on the web included on MSDN website.
The app authentication works fine but Azure add returned : Error loading external login information.
I checked inside the code by generating identity views, the app failed on:
var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null)
{
ErrorMessage = "Error loading external login information.";
return RedirectToPage("./Login", new { ReturnUrl = returnUrl });
}
await _signInManager.GetExternalLoginInfoAsync(); return null and return the error message.
The application is correctly configured in azure AD and it work from my app if I remove the authentication from the app.
I configured my app middlewares as follow:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddAuthentication(AzureADDefaults.AuthenticationScheme).AddCookie()
.AddAzureAD(options => Configuration.Bind("AzureAd", options));
services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
options.Authority = options.Authority + "/v2.0/";
options.TokenValidationParameters.ValidateIssuer = true;
});
And in configure method I added
app.UseAuthentication();
When I arrive on my login screen app (scaffolded by VS) all seems correct:
Login screen with two possibilities for authentication]:
Error message when i try Azure Active Directory method:
Can someone explain and help me to solve this problem?
Thanks in advance
The solution is to add cookieschemename as externalscheme. Below is sample code block in Startup.cs file.
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => { Configuration.Bind("AzureAd", options); options.CookieSchemeName = IdentityConstants.ExternalScheme; });
Unfortunately I had more or less the exact same problem. Although the Azure sample worked on its own, when I tried to integrate it to an existing application that uses Identity and other external authentication services, I could not get AzureAD to work. The interesting thing is that although in the output window I could see logging messages saying that the login was accomplished.
What I did (and this is more of a workaround rather than an exact solution to the problem) was to abandon using the Microsoft.AspNetCore.Authentication.AzureAD.UI package and I opted to go the longer way and configure OpenID manually for Azure. This article helped me immensely towards that end.
Having said that, I hope someone posts a more direct answer to your question.

ASP.NET Core 1.1 Combine Windows Authentication with Login Form as fallback

We are building a proof of concept application with ASP.NET Core 1.1 currently. The target is to provide SSO on intranet level and offer a login page for access via internet.
So far I am able to get the Kerberos ticket by setting "windowsAuthentication": true in the IIS settings (launchSettings.json) respectively web.config.
I build my own Authentication Middleware / Authentication Handler to go on.
If the user is not yet authenticated I am redirecting them to a login page.
BUT here comes my problem. The first request is always null, then the server challenges for Kerberos and gets the ticket. (May I miss the understanding of how Kerberos and challenging really works)
In my function HandleUnauthorizedAsync I can't know if the IIS is responding a ticket or not and therefore redirect them before the answer comes from the IIS.
Does anyone have tried something similar or has a clue to solve the problem?
Kind Regards
Edit:
Please be aware that this is currently only for proof of concept and testing stuff out.
HandleAuthenticateAsync:
if(Context.User?.Identity?.AuthenticationType == "Kerberos") {
var identity = new ClaimsIdentity(new GenericIdentity(Context.User.Identity.Name, AeroAuthenticationOptions.DefaultSchemaName), new Claim[] {
// get claims from claim store
});
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, new Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties { }, AeroAuthenticationOptions.DefaultSchemaName);
return AuthenticateResult.Success(ticket);
}
return AuthenticateResult.Skip();
HandleUnauthorizedAsync:
if(context == null) {
throw new ArgumentNullException(nameof(context));
}
var properties = new AuthenticationProperties(context.Properties);
var redirectUri = properties.RedirectUri;
if(string.IsNullOrEmpty(redirectUri)) {
redirectUri = OriginalPathBase + Request.Path + Request.QueryString;
}
var loginUri = Options.LoginPath + QueryString.Create(Options.ReturnUrlParameter, redirectUri);
var redirectContext = new AeroCookieRedirectContext(Context, Options, BuildRedirectUri(loginUri), properties);
await Options.Events.RedirectToLogin(redirectContext);
return true;