Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Authenticate from Active Directory but Authorize Roles from SQL Database in MVC

I am new to MVC. I searched and found no solution that fits for my requirements.

I am developing a web portal for our team's internal use which uses Windows AD authentication for login. However, for role based access I have created a local database which can return the Role details for the user. I have created a custom Authorization filter that allows me to handle authorization based on the user's role. This filter is querying details from the DB however the issue with this approach is, it will try to get details from DB for every request to the controller which makes it expensive.

How can I save the user details fetched from the DB in a Token such that I don't have to query DB for every request and use the Token values inside the Authorization filter. Also, I can use the values retrieved for the user from the database, anywhere else in the app. (There are some other details for the user we have in the Database).

If someone can suggest a better way to achieve this, please help.

Here is the code that I am currently using inside Authorization filter:

public class AuthorizeRole : AuthorizeAttribute
{
    private bool _authenticated;
    private bool _authorized;

    public string InRoles { get; set; }

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        base.HandleUnauthorizedRequest(filterContext);

        if (_authenticated && !_authorized)
        {
            filterContext.Result = new RedirectResult("/account/error");
        }
    }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        _authenticated = base.AuthorizeCore(httpContext);

        if (_authenticated)
        {
            if (string.IsNullOrEmpty(InRoles))
            {
                _authorized = true;
                return _authorized;
            }

            if (!string.IsNullOrEmpty(httpContext.User.Identity.Name))
            {
                string NTID = httpContext.User.Identity.Name.Split('\\')[1];
                var roles = InRoles.Split(',');

                using (Models.UserAuthEntities userAuthEntities = new Models.UserAuthEntities())
                {
                    try
                    {
                        ObjectResult<Models.Validate_User_Login_Result> userResults = userAuthEntities.Validate_User_Login(NTID);
                        var user = userResults.FirstOrDefault(all => all.NTID == NTID);

                        if (user == null)
                        {
                            _authorized = false;
                            return _authorized;
                        }
                        else
                        {
                            if (roles.Contains(user.Role))
                            {
                                return _authorized;
                            }
                        }
                    }
                    catch (Exception)
                    {
                        _authorized = false;
                        return _authorized;
                    }
                }
            }
            else
            {
                _authorized = false;
                return _authorized;
            }
        }

        _authorized = false;
        return _authorized;
    }
}

Please suggest at which section to use the code you will be suggesting (like, inside controller, inside filter or somewhere else.)

I found this solution at: this site but there it is used for AD groups.

like image 412
SavindraSingh Avatar asked Mar 01 '19 07:03

SavindraSingh


2 Answers

I have checked the cookie in override version of method AuthorizeCore it is working now:

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        string cookieName = FormsAuthentication.FormsCookieName;
        HttpCookie authCookie = httpContext.Request.Cookies[cookieName];
        _authenticated = base.AuthorizeCore(httpContext);
        string authToken = httpContext.Request.Headers["Auth-Token"];

        if (_authenticated)
        {
            if (authCookie == null)
            {
                if (string.IsNullOrEmpty(InRoles))
                {
                    _authorized = true;
                    return _authorized;
                }

                if (!string.IsNullOrEmpty(httpContext.User.Identity.Name))
                {
                    string NTID = httpContext.User.Identity.Name.Split('\\')[1];
                    var roles = InRoles.Split(',');

                    using (Models.UserAuthEntities userAuthEntities = new Models.UserAuthEntities())
                    {
                        try
                        {
                            ObjectResult<Models.Validate_User_Login_Result> userResults = userAuthEntities.Validate_User_Login(NTID);
                            var user = userResults.FirstOrDefault(all => all.NTID == NTID);

                            if (user == null)
                            {
                                _authorized = false;
                                return _authorized;
                            }
                            else
                            {
                                if (roles.Contains(user.Role))
                                {
                                    _authorized = true;
                                    return _authorized;
                                }
                            }
                        }
                        catch (Exception)
                        {
                            _authorized = false;
                            return _authorized;
                        }
                    }
                }
                else
                {
                    _authorized = false;
                    return _authorized;
                }
            }
        }

        _authorized = false;
        return _authorized;
    }
like image 163
SavindraSingh Avatar answered Sep 21 '22 13:09

SavindraSingh


First off, you might want to look at using AD Security Groups to manage access. That way OPS can continue to maintain access in a familiar time-tested platform and you dont have to write your own security definition interface.

As for the MVC security persistence All you have to do is add a manual log in to perform your above logic and then you use the built-in Membership Provider (for whatever version of MVC you are using) to log the user in. MVC will handle maintaining the logged in state and tokenising for you and you can specify things like timeout in the web.config (or settings.json in Core).

Sorry i dont have any sample code at hand for illustration.

like image 38
Stark Avatar answered Sep 20 '22 13:09

Stark