How to check if an Authenticated User has a specific claim AND the a Route segment is the same as the UserId? - authentication

I'm trying to see if it's possible in an ASP.NET-Core 2 web app, that if a User is authenticated in a request, we can also check in some Filter/ActionMethod Attribute:
They have a specific claim
The route has an string id segment (e.g. HttpPut[("{id}")] ) and that id segment needs to match the Auth'd User's Id.
Request includes a JWT header with the bearer token in it, which is used to 'create' the Authenticated Identity (which works 100% fine).
e.g.
HTTP PUT /accounts/PureKrome | User Id:PureKrome | Claim: Irrelivant. => Can continue. [You are updating yourself. Don't need any special claim when updating yourself].
HTTP PUT /accounts/PureKrome | User is Anonymous or Id:SomethingElse | Claim: irrelivant => Failure (Forbidden response) [Someone else is trying to update you and doesn't have the correct overriding claim. So fail]
HTTP PUT /accounts/SomeoneElse | User is Id:PureKrome | Claim: correct claim. => Can continue [Trying to update a different user BUT you have a claim that allows you to do that]
Right now, I do this in my ActionMethod code ... one of the first things. So I was just curious to see if this could be achieved using an Attribute that decorates the ActionMethod, instead.

That isn’t actually too complicated. All you need to do is have an authorization filter that looks at the route values and then checks it with the current user.
Something simple like this should already work fine:
public class ValidateUserIdRouteAttribute : Attribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
var user = context.HttpContext.User;
var requestedUserId = context.RouteData.Values["id"] as string;
var currentUserId = user.FindFirstValue(ClaimTypes.NameIdentifier);
if (requestedUserId != currentUserId &&
!user.HasClaim(c => c.Type == "may-edit" && c.Value == requestedUserId))
{
context.Result = new UnauthorizedResult();
}
}
}
And used on a route it would look like this:
[ValidateUserIdRoute]
[HttpGet("/account/update/{id}")]
public IActionResult UpdateAccount(string id)
{
// …
}
That’s all. If you have authentication set up properly, the Bearer token will be used to authenticate the user which may or may not set up the claims properly, and then you just check against those claims to see if accessing the route is allowed or not.
Of course, you can expand on this idea and add some more functionality to it, e.g. support different route data keys or something like that.

Related

How to get authorization header value in .NET Core Entity Framework

I am working with JWT tokens in my backend and my question is how I can read the value of the authorization header, when I have a [Authorize] annotation above my method. I need the token, because in its payload a user id is saved and I need the ID to perform several actions (of course the token gets verified first).
In my frontend, I am adding the authorize header as the following:
axios.post(finalurl, {accessToken: localStorage.accessToken}, {headers: {
'Authorization': `Bearer ${(localStorage.accessToken)}`
}})
In my backend:
[Authorize]
[HttpPut("{id}")]
public async Task<ActionResult<UserWithToken>> PutUser(int id, [FromForm] User user)
{
// ....
}
I know that it would also be possible to transfer the token as an object in the body, but this would make the thing more complicated, because when I am using this way I always have to create new Models that inherit from the object I want to transfer and gets an additional token attribute.
If you simply want to get the user ID and it's stored as a claim in the token, you can get it through the HttpContext like so:
HttpContext.User?
.Claims?
.FirstOrDefault(c => c.Type == JwtRegisteredClaimNames.Sub)?
.Value
Of course, if you use a different claim type, you can replace JwtRegisteredClaimNames.Sub with whatever your claim is called.
HttpContext.User is the ClaimsPrincipal of the user associated with the current request.
try this:
public async Task<ActionResult<UserWithToken>> PutUser(int id, [FromForm] User user)
{
var token = string.Empty;
var header = (string)HttpContext.Request.Headers["Authorization"];
if (header != null) token = header.Substring(7);
.....
}
You can also try the following method by adding a parameter [FromHeader] which is working
[Authorize]
[HttpPut("{id}")]
public async Task<ActionResult<UserWithToken>> PutUser(int id, [FromForm] User user, [FromHeader] string authorization)
{
// ....
}

Yii2 Authentication not working as expected

I am working on a micro service. It has basically login and registration. I followed the Yii2 official guide. But now i am facing an issue. When i try to send request to the endpoints which are protected ( Only users with access_token can make request ) It works but very strange it checks all the rows in the database and if access_token is matches any rows in the database then it allows the request. But what i want - I am trying to get users information, if i pass the token i want only the information which belongs to current user ( Whose token is in request ) .
I am doing this in my UserController -
public function behaviors() {
$behaviors = parent::behaviors();
$behaviors['authenticator'] = [
'class' => HttpBearerAuth::className(),
];
$behaviors['authenticator']['only'] = ['view'];
return $behaviors;
}
And in User model have implemented this method -
public static function findIdentityByAccessToken($token, $type = null) {
return static::findOne(['access_token' => $token]);
}
Where i am doing wrong?
If the access_token in the request matches the access_token value for any of the users in the database, then, like you say, the authentication filter will forward the request to the corresponding action on your controller.
At this point the application user component points to the user that was found, you can use the user's component id to recover the record matching the request's user from the database.
// Get the user record
$current_user = Yii::$app->user->identity;
// Do something with the user record
return [
'username' => $current_user->username,
'last_update' => $current_user->updated_at
...
];

Auth0 Get userId in response payload?

When a user logins using the Auth0 lock on my client side, I get an idToken, but also an idTokenPayload which looks like this:
idTokenPayload = {
audience: "AUTH0CLIENTID",
exp: 1494190538,
iat: 1494154538,
iss: "AUTH0DOMAIN"
sub: "USERNAME"
};
Would it be possible to return the userId in Auth0's database instead of the username in the sub field?
The reason I want to do this is that I want to keep Auth0's db for users, and I have on my server-side some Profile, Post, Comment etc entities which have a userId column. Right now before each request on my entities I need to populate the user by doing an extra request: let id = Profile.find("... where username === auth0.sub").getId(); (pseudo-code of course).
With the C# lock sdk, you get back an Auth0User after the call to the LoginAsync method in the Auth0 client. Let's call this variable auth0User. If I look at auth0User.Profile, a JObject (it's a JSON object if you're not using C#), it contains a JSON array named "identities". My identities variable initialization looks like:
var identities = (JArray)auth0User.Profile["identities"];
This array contains all the identity providers associated with the user. If like me you haven't attached any other sign in besides Auth0, there will be just 1 entry here. Each object in this JSON array will contain a "provider" string and a "user_id" string. If the provider says "auth0" then it's from Auth0. Since I don't use FB or other account types I'm not exactly sure what they say. Here's my C# code to get the UserID:
var identities = (JArray)auth0User.Profile["identities"];
if (identities != null)
{
foreach (var identity in identities)
{
var provider = (string)identity["provider"];
if (string.Equals(provider, "auth0"))
{
UserID = (string)identity["user_id"];
break;
}
}
}
I believe that this should all be provided standard without needing to add any rules or webhooks. This article should explain in more detail and also gives examples in javascript: auth0 normalized user profile

Laravel Authentication with condition

I am using Laravel 5.1 and Laravel's default authentication system.
In database (MySQL) I add a new column named 'role'. The value will be 1 for admin and 2 for members.
Now I want to give login permission only for admin, means where the value is 1. How can I do that?
Actually I solved it. I just add these code in postLogin() method of AthenticatesUsers.php method.
// If role is equal to 1, user allowed to login
// You can change $admin value anytime according to database Design
// Example: In role column the value for admin is 2 or A. You just need to change the value of $admin.
$userData = User::select('role')->where('email',$request['email'])->first();
$admin = 1;
$role = $userData->role;
if($role == $admin){
$request['role'] = $role;
}
I feel that there are better ways to achieve what you're after, such as middleware, however given what you're after this would be one way to do it.
Upon logging in a user us sent to 'home', unless you specify otherwise in the AuthController.
Inside your routes.php, if you just set up a GET route to point to a HomeController (or whatever you name it) then you could use a function to run the tests you're after.
routes.php
Route::get('home', 'HomeController#index');
HomeController
public function index()
{
//If they are yet to log in then return your normal homepage
if (Auth::guest())
{
return View::make('home');
}
else
{
//Run your tests here to check their role and direct appropriately
//Given you have added the role column to the users table, you can access it like so:
//Auth::user()->role
}
}

Claims based authorization with ASP.NET MVC

I was reading up a lot of blog posts and stackoverflow answers but still I am unable to find a real world open source project which uses claims based authentication and authorization, so that I can get an idea on how to actually implement these.
So far what I could find is Thinktecture.IdentityModel and this blog implements a claims based authorization on a sample website. If you guys could point me some Open source projects using claims, that would be really helpful.
What I am interested is how to retrieve claims for my application using the database.
So far, what I have tried is that using an in memory claims store to simulate the databsae, I have created a CustomClaimsTransformer and CustomAuthorisationManager like this.
public class CustomClaimsTransformer : ClaimsAuthenticationManager
{
public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
{
//validate name claim
string nameClaimValue = incomingPrincipal.Identity.Name;
return CreatePrincipal(nameClaimValue);
}
private ClaimsPrincipal CreatePrincipal(string userName)
{
int userId = ClaimStore.Users.First(u => u.Value == userName).Key;
var claims = ClaimStore.ClaimsSet.Where(c => c.Key == userId);
var claimsCollection = claims.Select(kp => kp.Value).ToList();
return new ClaimsPrincipal(new ClaimsIdentity(claimsCollection, "Custom"));
}
}
public class CustomAuthorisationManager : ClaimsAuthorizationManager
{
public override bool CheckAccess(AuthorizationContext context)
{
string resource = context.Resource.First().Value;
string action = context.Action.First().Value;
if (action == "Show" && resource == "Code")
{
bool likesJava = context.Principal.HasClaim(ClaimStore._httpMyclaimsUsers, "True");
return likesJava;
}
else if (action == "Read" && resource == "Departments")
{
bool readDeps = context.Principal.HasClaim(ClaimStore._httpMyclaimsDepartments, "Read");
return readDeps;
}
return false;
}
}
How to implement these in a real world scenario without having too many IF conditions?
Try the following link , it seems like a decent solution
http://developers.axiomatics.com/blog/index/entry/custom-claims-based-authorization-in-net-using-axiomatics-pep-sdk-for-net.html
Also you can define your policy and load it
http://msdn.microsoft.com/en-us/library/system.security.claims.claimsauthorizationmanager.loadcustomconfiguration.aspx
How to: Implement Claims Authorization in a Claims-Aware ASP.NET Application Using WIF and ACS
http://msdn.microsoft.com/en-us/library/gg185907.aspx
I finally managed to design my own system with the required functionality using the existing asp.net identity 2.0 tables + a few of my own.
I'm gonna call every AREA-CONTROLLER-ACTION trio as resources in my system. WebAPI included. Area itself is a resource. Controller itself is a resource. Action itself is a resource. Any combination of them, is also a resource. I'll auto generate everything from the system itself using reflection.
Also, I'm going to use the same AspNetRoles table to store my User Groups. Users belong to one or more groups (Super Admin, Admin, Agent, Client etc.).
Using the existing Role based model as a user group based model with claims, I could get it working.Super admins are on god mode. They can create lower level users/groups/assign permissions etc.
Users can have special permissions. For example, Everyone in Agent group is denied access to updating a hotel, but a special agent who might also be the owner of a hotel can be given specific access to updating only their hotel.
Since the entire access control system runs on MVC area-controller-action sets. No one initially has no access (including super admins) and we gradually define which parts the groups/users has access to. And we give super admins and admins exclusive access through a claim. Access to everywhere is denied by default.
Once I Auto generated the AREA-CONTROLLER-ACTION sets, I let the user select which group has access to which item.
When the user logs in, I get all the resources the current user has access to and store them as claims. Based on that, using a claims auth manager, when a user request access to some resource, I can check their claims and decide if they should be given access to.
foreach(var claim in permissionClaims) {
var parts = claim.Value.Split(new [] {
'|'
}, StringSplitOptions.None);
if (parts.Length == 3) {
//var httpMethod = parts[0];
var action = parts[1];
var api = parts[2];
//Current.Log.Warn("Checking Access : " + req + " [action: " + action + "]");
// is this request for a API action?
if (api.Contains("API")) {
// if so, req must be for a API action
if (req.Contains("Api") && action.Contains(req)) {
Log.Trace("User has access to API : " + req + " [action: " + action + "]");
return true;
}
} else {
// this is for a MVC action
if (action.Contains(req)) {
Log.Trace("User has access to MVC : " + req + " [action: " + action + "]");
return true;
}
}
}
}
I have explained the approach in detail here - ASP.NET MVC Fine Grained Identity & Access Control.