1

I have project with Windows Authentication and with a controller I have a question, by that controller below, I can get information by specifying the name of branch (by typing URL into a browser address bar for example):

"http://localhost:62249/Students/TestNew/Branch1";

And it will display to the user data where branch = Branch1.

Now the question is - how can I achieve the following?

For each branchname I want specify permission to allow open this page by specifying group from ActiveDirectory. Or it's impossible and I should create 10 more controllers and specify there permission for each one.

    [HttpGet]
    public ActionResult TestNew(string branchname)
    {
        // check stuff like permissions
        var db = new MovieContext();
        var model = new Model();


        var students = db.Student
            .Where(x => x.BranchName == branchname)
            .GroupBy(x => new { x.BranchName, x.Name, x.Currency, x.NoCart, x.NoAccount })
            .Select(x => new
            {
                BranchName = x.FirstOrDefault().BranchName,
                Name = x.FirstOrDefault().Name,
                A_Status = x.Max(p => p.A_Status),
                Currency = x.FirstOrDefault().Currency,
                NoCart = x.FirstOrDefault().NoCart,
                NoAccount = x.FirstOrDefault().NoAccount
            }).ToList();
        foreach (var item in students)
        {
            model.Students.Add(new Student
            {
                A_Status = item.A_Status,
                BranchName = item.BranchName,
                Name = item.Name,
                NoAccount = item.NoAccount,
                NoCart = item.NoCart,
                Currency = item.Currency

            });
        }
        return View(model);

1 Answer 1

2

You can use Policy based authorization https://learn.microsoft.com/en-us/aspnet/core/security/authorization/policies?view=aspnetcore-2.1 and use an authorization Handler in your foreach loop to check if current user is allowed to access the ressource.

Here's an example of what I did except that I use groups in my db rather than AD groups :

first you create a requirement it can be emtpy or not depending on your needs, as in Microsoft docs it can contains your group name.

 public class CIAssetManagementRequirement : IAuthorizationRequirement
{
}

Then your Policy, the purpose of this class is to return context.Succeed(requirement); when user is allowed to perform an action :

 public class CIAuthoringManagement : AuthorizationHandler<CIAuthoringManagementRequirement, ConfigurationItem>
{
    private readonly MyAppContext _context;

    public CIAuthoringManagement(MyAppContext context)
    {
        _context = context;
    }

    [DebuggerStepThrough]
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CIAuthoringManagementRequirement requirement, ConfigurationItem resource)
    {
        var user = _context.Users.Include(u => u.Groups).Include(u => u.Employer).Include(c => c.AuthoringCatalogs).AsNoTracking().SingleOrDefault(m => m.ID == context.User.GetUniqueIdentifier());

        if (user != null)
        {
            //Allowing SuperAdmins by default
            var group = _context.Groups.Include(g => g.Users).ThenInclude(g => g.User).AsNoTracking().SingleOrDefault(g => g.DisplayName == "SuperAdmins");
            if (group != null)
            {
                var groupUsers = new HashSet<Guid>(group.Users.Select(u => u.User.ID));
                if (groupUsers.Contains(user.ID))
                {
                    context.Succeed(requirement);
                }
            }

            //Allowing CI if it's part of the catalogs where CI is author
            //hashset of id where user is declared author
            var authorCatalogHS = new HashSet<Guid>(user.AuthoringCatalogs.Select(c => c.CatalogId));

            if (resource.Catalogs != null)
            {
                foreach (var catalog in resource.Catalogs)
                {
                    if (authorCatalogHS.Contains(catalog.CatalogId))
                    {
                        context.Succeed(requirement);
                    }
                }
            }
            else
                context.Succeed(requirement);

        }

        return Task.CompletedTask;
    }
}

You instanciate your Policy in your startup :

services.AddAuthorization(options =>
        {
            // require user to have cookie auth or jwt bearer token
            options.AddPolicy("Authenticated",
                policy => policy
                    .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme, CookieAuthenticationDefaults.AuthenticationScheme)
                    .RequireAuthenticatedUser());
                              options.AddPolicy("CIAuthoringManagement",
                policy => policy.Requirements.Add(new CIAuthoringManagementRequirement()));

                       });
services.AddTransient<IAuthorizationHandler, CIAuthoringManagement>();

And finally in your controller :

foreach (var ciApplication in _context.CIApplications.AsNoTracking())
                    {
                        if ((await _authorizationService.AuthorizeAsync(User, ciApplication, "CIAuthoringManagement")).Succeeded)
                        {

                            CIApplications.Add(ciApplication);
                        }
                    }
return CIApplications;
Sign up to request clarification or add additional context in comments.

2 Comments

I'm not using an ASP.NET CORE or it's also possible in ASP.NET MVC 5?
I haven't tried but this project brings policies to MVC 5. github.com/pschaeflein/mvc5-authorization-policy

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.