How does authentication work or how to make protection from the mega-hacker Mr. Bob? - asp.net

I`m developing angular + asp.net mvc app without Claim, JWT and other built-in tools.
My auth (authentication) system:
"Users" table:
namespace AwakenedTalents.Models
{
public class User
{
public string Id { get; set; } // I use guid here
public string Login { get; set; }
public string Password { get; set; }
public string Email { get; set; }
public bool IsEmailConfirmed { get; set; }
}
}
When I login to the site, I send an encrypted (TrippleDES by key) Id from the ASPNET server and add it to the cookies on angular.
AuthenticationCheck (angular AuthService method):
IsAuth(): boolean {
if (this.cookies.get("authtoken")!="")
{
return true;
}
else
{
return false;
}
}
Thus, I check if the user is authenticated and call the command to get user data from the server:
UpdateUserData() {
$.get(env.environment.server_url+"/login/getuserdata?authtoken=" + this.cookies.get("authtoken")).done(response => {
if( response != "Not authenticate"){
userData.user = JSON.parse(response);
}
})
return userData.user;
}
Everything seems to be working fine until the mega-hacker Mr. Bob shows up. He steals other people's cookies in ANY way and replaces them with his own. Then he enters the site under the guise of another person, stealing his data. How to make protection from the mega-hacker Mr. Bob?
What did you try and what were you expecting? :
I watched youtube videos :)

You can protect your cookies by making them with the secure flag and the httponly flag. The secure flag will makes sure your cookie is only sent over an encrypted (https) connection. The httponly flag makes your cookie inaccessible to javascript. https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies
It's also a good idea to have verification information that you can validate in your cookie, such as including the sessionID as part of the encrypted content to validate it against the current user's session.

Related

Proactive messaging throwing Operation returned an invalid status code 'Unauthorized'

I'm trying to store the conversation reference for chats between user and our bot, and use that chat reference to send other messages later.
I'm saving the following entities in our DB:
string UserAadObjectId { get; set; }
string UserId { get; set; }
string UserName { get; set; }
string ConversationId { get; set; }
string ConversationType { get; set; }
string ConversationTenantId { get; set; }
string ChannelId { get; set; }
string ActivityId { get; set; }
string BotId { get; set; }
string BotName { get; set; }
string ConversationReference { get; set; }
string ServiceUrl { get; set; }
After getting these entities for a specific user, I'm creating a conversation reference as following:(Where chatReference is the sql database for the entities above)
var user = new ChannelAccount(chatReference.UserId, chatReference.UserName, null, chatReference.UserAadObjectId);
var bot = new ChannelAccount(chatReference.BotId, chatReference.BotName);
var conversationAccount = new ConversationAccount(conversationType: chatReference.ConversationType, id: chatReference.ConversationId, tenantId: chatReference.ConversationTenantId);
var convReference = new ConversationReference(activityId: chatReference.ActivityId, user: user, bot: bot, conversation: conversationAccount, channelId: chatReference.ChannelId, serviceUrl: chatReference.ServiceUrl);
When running:
await turnContext.SendActivityAsync(messageActivity);
I'm getting the following error from Bot Connector I think:
Operation returned an invalid status code 'Unauthorized'
{"message":"Authorization has been denied for this request."}
Why this is happening? Knowing that AppId and AppPwd are correct.
There are series of steps to be followed to avoid the error occurred.
1. Disable security and test on localhost
Check the App ID and password in configuration file and delete those for testing
"MicrosoftAppId": "",
"MicrosoftAppPassword": ""
As you are using the core .Net framework. add or edit settings in appsettings.json
2. Check the App ID and password of bot
Now need to check whether the App ID and password are matching or not.
These instructions and procedure include CURL usage
To verify that your bot's app ID and password are valid, issue the following request using cURL, replacing APP_ID and APP_PASSWORD with your bot's app ID and password.
curl -k -X POST https://login.microsoftonline.com/botframework.com/oauth2/v2.0/token -d "grant_type=client_credentials&client_id=APP_ID&client_secret=APP_PASSWORD&scope=https%3A%2F%2Fapi.botframework.com%2F.default"
This request attempts to exchange your bot's app ID and password for an access token. If the request is successful, you will receive a JSON payload that contains an access_token property, amongst others.
{"token_type":"Bearer","expires_in":3599,"ext_expires_in":0,"access_token":"eyJ0eXAJKV1Q..."}
3. Enable security and test on localhost
<appSettings>
<add key="MicrosoftAppId" value="APP_ID" />
<add key="MicrosoftAppPassword" value="PASSWORD" />
</appSettings>
if you are using bot framework SDK for .NET use the above code block
For complete reference of the procedure. Check

How to get the notification that a user has been successfully logged in?

When user is logged in, I'd like to fetch user's profile data so that I can display them throughout the application.
<CascadingValue Value="#UserProfile">
<div class="content px-4">
#Body
</div>
</CascadingValue>
I'd like to be able to intercept a request so that I can check 1) the user is logged in and 2) the UserProfile object is set. If the user's logged in but the object is not set then I'll make a request to the API to get data.
Here's the portion of the App.razor code.
<Found Context="routeData">
<AuthorizeRouteView RouteData="#routeData" DefaultLayout="#typeof(MainLayout)">
<NotAuthorized>
#if (!context.User.Identity.IsAuthenticated)
{
<RedirectToLogin />
}
else
{
<p>You are not authorized to access this resource.</p>
}
</NotAuthorized>
<Authorizing>
</Authorizing>
</AuthorizeRouteView>
</Found>
<Authorizing></Authorizing> can be used for when the authentication process is going on. How do I know when the process is done and that the user's logged in, so that I can fetch user's profile.
Thanks for helping.
The answer is the RemoteAuthenticatorView component on the Authenticator.razor page. This component exposes all sort of properties that covers so many scenarios, i.e. OnLogInSucceeded, OnLogOutSucceeded, OnLogOutFailed, and so forth.
In my case, I wanted to queries user's profile data as soon as the login succeeds so I can display which organization's he/she belongs to.
#page "/authentication/{action}"
#using Microsoft.AspNetCore.Components.WebAssembly.Authentication
<RemoteAuthenticatorView
AuthenticationState="RemoteAuthenticationState"
OnLogInSucceeded="#RestoreAppState" //this is the event I was looking for
Action="#Action" />
OnLoggInSucceeded is what I was looking for
public partial class Authentication
{
[Inject] AppState AppState { get; set; }
[Inject] HttpClient Http { get; set; }
[Parameter] public string Action { get; set; }
public AppAuthenticationState RemoteAuthenticationState { get; set; } =
new AppAuthenticationState();
protected override void OnInitialized()
{
if (RemoteAuthenticationActions.IsAction(RemoteAuthenticationActions.LogIn, Action))
{
// Preserve the current order so that we don't loose it
//RemoteAuthenticationState.Order = OrderState.Order;
}
}
private async Task RestoreAppState()
{
if (string.IsNullOrEmpty(AppState.RootInstitutionName))
{
try
{
var profileData = await Http.GetFromJsonAsync<UserProfileData>("userprofiles");
AppState.RootInstitutionName = profileData.RootInstitution.InstitutionName;
}
catch (AccessTokenNotAvailableException exception)
{
exception.Redirect();
}
}
}
}
There's even a possibility to preserve data between operations, such login, logout. It was good to watch Daniel Roth explaining security works in Blazor.

.NET Core SignalR: How to accomplish resource-based authorization?

All my SignalR clients connect using a JWT bearer token. I utilize the [Authorize] attribute in my SignalR Hub.
This token contains a userId which can be used to check if a user has read access on the resource through the resource's users property which contains a List<PuppyUserPermission> that look like this:
public class PuppyUserPermission
{
public string userId { get; set; }
public bool read { get; set; }
public bool write { get; set; }
}
The question is: how do I connect the dots here? Ideally, instead of something like
[Authorize]
public class PuppyHub : Hub
{
public async Task SendPuppy(Puppy pup)
{
await Clients.All.SendAsync(pup);
}
}
I would so something like the following (this is more pseudo code than anything else, as I don't use valid methods):
[Authorize]
public class PuppyHub : Hub
{
public async Task SendPuppy(Puppy pup)
{
var clients = Puppy.users.Where(u => u.read == true);
await clients.SendAsync(pup);
}
}
Basically, I'd like to ensure that the clients recieving the Puppy object via SignalR would be authorized users on the resource. Problem is, Clients is just a list of string client IDs, and I'm not sure how to go about tying them to actual users on my Puppy resource.
How do I go about achieving this?
From the beginning, I had the feeling that the answer lay in IUserIdProvider, but I didn't see how that would work for multiple users.
I finally found the answer, but it'll definitely need some cleanup.
First, create your own implementation of IUserIdProvider as follows:
public class MyUserIdProvider : IUserIdProvider
{
public string GetUserId(HubConnectionContext connection)
{
var username = connection.User.Claims.Where(x => x.Type == "THE_CLAIM_YOU_WANT_TO_USE_TO_IDENTIFY_USERS").First().Value;
return username;
}
}
Next, register it using DI:
services.AddSingleton<IUserIdProvider, MyUserIdProvider >();
Now, when you want to send events from the server, use DI in your constructor to pull down an instance of your SignalR Hub as per usual:
private IHubContext<PuppyHub> puppyHub { get; }
public UsersController(IHubContext<PuppyHub> _puppyHub)
{
puppyHub = _puppyHub;
}
Then, where when you want to tell your clients about the new Puppy:
// ... typical controller code
// assume we have a var, puppy, with a list of authorized users
// use System.Linq to get a list of userIds where the user is authorized to read the puppy
var authorizedUsers = (IReadOnlyList<string>)puppy.users.Where(x => x.permissions.read == true).Select(i => i._id).ToList();
// send the new puppy to the authorized users
await puppyHub.Clients.Users(authorizedUsers).SendAsync("SendPuppy", puppy);
And viola! You have now done resource-based authorization with SignalR.

Is there much authentication overhead when WebAPI makes a request to the server?

From what I understand. Every time a webapi request goes to the server then it's authenticated. My application uses WebAPI 2, Identity 2 and has get methods such as this:
/api/cityStatusList
/api/cityTypeList
/api/cityOptionList
These calls exist to get data for a page.
If the webapi is authenticating every request then should I look into how I can combine all these requests into one?
If the webapi is authenticating every request then should I look into how I can combine all these requests into one?
Why, is it causing any trouble?
You can of course define and return a class like this:
public class CityData
{
public List<CityStatus> StatusList { get; set; }
public List<CityType> TypeList { get; set; }
public List<CityOption> OptionList { get; set; }
}
Create CityView model class for your city like following :
public class CityView
{
public List<cityStatusView> cityStatusList { get; set; }
public List<cityTypeView> cityTypeList { get; set; }
public List<cityOptionView> cityOptionList { get; set; }
}
public class cityStatusView
{
public int ID { get; set; }
}
public class cityTypeView
{
public int ID { get; set; }
}
public class cityOptionView
{
public int ID { get; set; }
}
use it like following code in your web api :
// View model
var cityStatusList=..;
var cityTypeList=..;
var cityOptionList=..;
CityView objVM = new CityView();
objVM.cityStatusList = cityStatusList;
objVM.cityTypeList = cityTypeList;
objVM.cityOptionList = cityOptionList;
return ActionContext.Request.CreateResponse(HttpStatusCode.OK, objVM);
To address the question directly - yes, it is authenticating your application every time. However, on the scale of standard web-application this time is don't-you-even-worry-about-it miniscule.
Combining those routes into one might well be a good idea not because authentication has to happen multiple times, but because a web request can simply take a while. Typically this is due to the time it takes to physically send signals from the server to the client over TCP/IP (and re-send to compensate for any dropped packets). Even when parallelizing requests, fewer web requests is faster.
That being said, by default I would do the simplest thing possible and not worry about it. What I just mentioned is an optimization, should be treated as such, and not done prematurely.
As for authentication? It's just a few steps of the super-marathon that is your web request, it really doesn't matter. Someone correct me if I'm wrong, but I don't think it usually even hits the database - all it has to do is decode the claims that are stored in a cryptographically-secure fashion in the authentication cookie.

Basic authentication in ASP.NET MVC 5

What steps must be done to implement basic authentication in ASP.NET MVC 5?
I have read that OWIN does not support cookieless authentication, so is basic authentication generally possible?
Do I need a custom attribute here? I am not sure about how these attributes work.
You can use this simple yet effective mechanism using a custom ActionFilter attribute:
public class BasicAuthenticationAttribute : ActionFilterAttribute
{
public string BasicRealm { get; set; }
protected string Username { get; set; }
protected string Password { get; set; }
public BasicAuthenticationAttribute(string username, string password)
{
this.Username = username;
this.Password = password;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var req = filterContext.HttpContext.Request;
var auth = req.Headers["Authorization"];
if (!String.IsNullOrEmpty(auth))
{
var cred = System.Text.ASCIIEncoding.ASCII.GetString(Convert.FromBase64String(auth.Substring(6))).Split(':');
var user = new { Name = cred[0], Pass = cred[1] };
if (user.Name == Username && user.Pass == Password) return;
}
filterContext.HttpContext.Response.AddHeader("WWW-Authenticate", String.Format("Basic realm=\"{0}\"", BasicRealm ?? "Ryadel"));
/// thanks to eismanpat for this line: http://www.ryadel.com/en/http-basic-authentication-asp-net-mvc-using-custom-actionfilter/#comment-2507605761
filterContext.Result = new HttpUnauthorizedResult();
}
}
It can be used to put under Basic Authentication a whole controller:
[BasicAuthenticationAttribute("your-username", "your-password",
BasicRealm = "your-realm")]
public class HomeController : BaseController
{
...
}
or a specific ActionResult:
public class HomeController : BaseController
{
[BasicAuthenticationAttribute("your-username", "your-password",
BasicRealm = "your-realm")]
public ActionResult Index()
{
...
}
}
In case you need additional info check out this blog post that I wrote on the topic.
You can do this with a custom attribute. There is an implementation of a custom attribute that supports base authentication in the open source project SimpleSecurity, which you can download here. There is a reference application to demonstrate how it is used. It was originally developed to work with SimpleMembership in MVC 4 and has been recently ported to use ASP.NET Identity in MVC 5.
I wanted to amend the answer shared by Darkseal, because that code has a major security flaw. As written, that action filter does not actually terminate the request when res.End() is called. The user is prompted for credentials and a 401 response is returned if the credentials don't match, but the controller action is still executed on the server side. You need to set the filterContext.Result property to something in order for the request to terminate properly and not continue to the action method.
This was particularly bad for my situation, as I was trying to protect a web service endpoint that receives a data feed from a third party. As written, this action filter didn't protect anything because the data was still being pushed through my action method.
My "quick fix" is below:
public class BasicAuthenticationAttribute : ActionFilterAttribute
{
public string BasicRealm { get; set; }
protected string Username { get; set; }
protected string Password { get; set; }
public BasicAuthenticationAttribute(string username, string password)
{
this.Username = username;
this.Password = password;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var req = filterContext.HttpContext.Request;
var auth = req.Headers["Authorization"];
if (!String.IsNullOrEmpty(auth))
{
var cred = System.Text.ASCIIEncoding.ASCII.GetString(Convert.FromBase64String(auth.Substring(6))).Split(':');
var user = new { Name = cred[0], Pass = cred[1] };
if (user.Name == Username && user.Pass == Password) return;
}
var res = filterContext.HttpContext.Response;
res.AddHeader("WWW-Authenticate", String.Format("Basic realm=\"{0}\"", BasicRealm ?? "Ryadel"));
filterContext.Result = new HttpUnauthorizedResult();
}
}
Great answer from #Darkseal. Here's the same code repurposed for use with ASP.NET Web API (close cousin to MVC). Same idea, slightly different namespaces and context classes. Add it to your classes and methods in exactly the same way.
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
public class BasicAuthenticationAttribute : ActionFilterAttribute
{
public string BasicRealm { get; set; }
protected string Username { get; set; }
protected string Password { get; set; }
public BasicAuthenticationAttribute(string username, string password)
{
Username = username;
Password = password;
}
public override void OnActionExecuting(HttpActionContext filterContext)
{
var req = filterContext.Request;
var auth = req.Headers.Authorization;
if (auth?.Scheme == "Basic")
{
var cred = Encoding.ASCII.GetString(Convert.FromBase64String(auth.Parameter)).Split(':');
var user = new { Name = cred[0], Pass = cred[1] };
if (user.Name == Username && user.Pass == Password) return;
}
filterContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
filterContext.Response.Headers.Add("WWW-Authenticate", string.Format("Basic realm=\"{0}\"", BasicRealm ?? "YourRealmName"));
}
}
HTTP basic authentication doesn't require a cookie. It's based on a HEADER in the HTTP request. The header is named Authorization and its value should be username and password combined into a string, "username:password" (all base64 encoded).
Sincerely I never used basic authentication with ASP.NET MVC, but I used Web API to create a custom attribute (you can start from here for WebAPI or here for MVC).
you can try this package on Nuget (AuthPackage)
its enables you to add authentication to your asp.net mvc easily.
install package using Package Manager Console:
Install-Package AuthPackage
add Connection String to your Web.config in (appSettings):
<add key="connectionString" value="connectionStringHere" />
you're ready to register users, login, logout
example:
public async Task<ActionResult> SignIn()
{
var context = System.Web.HttpContext.Current;
AuthUser authUser = new AuthUser(context);
await authUser.SignIn("waleedchayeb2#gmail.com", "123456");
return RedirectToAction("Index", "Home");
}
You can read the Documentation here
The Darkseal’s answer
[BasicAuthenticationAttribute("your-username", "your-password",
BasicRealm = "your-realm")]
has 2 disadvantages :
name and password are hardcoded and they support only single user.
More flexible solution should support multiple username/password pairs stored in configuration.
Microsoft describes a sample https://gm/aspnet/samples/tree/main/samples/aspnet/WebApi/BasicAuthentication.
public abstract class BasicAuthenticationAttribute : Attribute, IAuthenticationFilter
In overload of
abstract Task<IPrincipal> AuthenticateAsync(string userName, string password,
CancellationToken cancellationToken);
you can implement check to find if username/password from the header exist in configuration/secret list of username/password pairs
It’s also possible to create HTTP module that performs Basic Authentication. You can easily plug in an ASP.NET membership provider by replacing the CheckPassword method.
https://learn.microsoft.com/en-us/aspnet/web-api/overview/security/basic-authentication#basic-authentication-with-custom-membership
Example of OWIN implementation https://github.com/scottbrady91/Blog-Example-Classes/tree/master/OwinBasicAuthentication/WebApi
Possible implementation in .Net core is described in
https://github.com/mihirdilip/aspnetcore-authentication-basic
An application of ours "accidentally" used basic authentication because of the following code in Web.config:
<system.webServer>
<modules>
<remove name="FormsAuthentication" />
</modules>
... other stuff
</system.webServer>
The application is otherwise configured to use forms authentication.
The browser authentication window popped up whenever normal forms authentication would otherwise have been used.

Resources