Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET Identity - Custom Implementation with Multi-Provider

I'm currently working on a big project for car dealers and I have a dilemma.

Should I use ASP.NET Identity or old school FormsAuthentication?

I need to be able to login via 2 providers. First, the user is always in the database, but we check if it is a LDAP user, if so, authenticate it via LDAP (I use a WebService for that which has a Login method).

Here's my Login method:

    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Login(LoginModel model)
    {
        if (ModelState.IsValid)
        {
            var userInDb = this.db.Users.FirstOrDefault(u => u.Username == model.username);

            if (userInDb != null)
            {
                // USER EXISTS
                if (userInDb.IsLdap)
                {
                    try
                    {
                        // IS LDAP POWERED, IGNORE PASSWORD IN DB
                        using (var ws = WebServiceClient.Factory(model.GetDomain()))
                        {
                            // MAKE AUTH
                            var result = await ws.Login(model.GetUsername(), model.password);

                            if (result.Success)
                            {
                                // USER IS LEGAL
                                FormsAuthentication.SetAuthCookie(model.username, model.remember);

                                return RedirectToAction("Init");
                            }
                            else
                            {
                                // USER IS ILLEGAL
                                ModelState.AddModelError("", "Username or password invalid.");
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        // AN ERROR OCCURED IN CREATION OF THE WebService
                        ErrorUtils.Send(ex);

                        ModelState.AddModelError("", ex.Message);
                    }
                }
                else
                {
                    // USER IS DB POWERED, CHECK THE PASSWORDS
                    var currentHash = userInDb.Password;

                    var isPasswordOkay = PasswordUtils.Validate(model.password, currentHash);
                    if (isPasswordOkay)
                    {
                        // USER PASSWORD IS LEGIT
                        FormsAuthentication.SetAuthCookie(model.username, model.remember);

                        return RedirectToAction("Init");
                    }
                    else
                    {
                        // BAD PASSWORD
                        ModelState.AddModelError("", "Username or password invalid.");
                    }
                }
            }
            else
            {
                try
                {
                    // USER DO NOT EXISTS IN DB
                    using (var ws = WebServiceClient.Factory(model.GetDomain()))
                    {
                        // MAKE AUTH
                        var result = await ws.Login(model.GetUsername(), model.password);

                        if (result.Success)
                        {
                            // USER IS LEGAL IN LDAP SO CREATE IT IN DB
                            var ldapUser = (AuthResponse.AuthResponseUser)result.User;

                            var name = ldapUser.DisplayName.Split(' ');
                            var user = new User()
                            {
                                Firstname = name[0],
                                Lastname = name[1],
                                ActivatedAt = DateTime.Now,
                                ModifiedAt = DateTime.Now,
                                Email = model.username,
                                IsLdap = true,
                                Username = model.username,
                                Password = "",
                                Notifications = NotificationType.All
                            };

                            // GET THE DEALER TO ADD IT TO THE USER RIGHT NOW
                            var dealer = this.db.BaseContexts.Find(ws.Dealer.Id);
                            user.BaseContexts.Add(dealer);
                            dealer.Users.Add(user);

                            try
                            {
                                this.db.Users.Add(user);

                                this.db.Entry(user).State = System.Data.Entity.EntityState.Added;
                                this.db.Entry(dealer).State = System.Data.Entity.EntityState.Modified;

                                await this.db.SaveChangesAsync();

                                FormsAuthentication.SetAuthCookie(model.username, model.remember);

                                return RedirectToAction("Init");
                            }
                            catch (Exception ex)
                            {
                                ErrorUtils.Send(ex);

                                ModelState.AddModelError("", "An error occured during user creation.");
                            }
                        }
                        else
                        {
                            // USER IS ILLEGAL
                            ModelState.AddModelError("", "Username or password invalid.");
                        }
                    }
                }
                catch (Exception ex)
                {
                    // AN ERROR OCCURED IN CREATION OF THE WebService
                    ErrorUtils.Send(ex);

                    ModelState.AddModelError("", ex.Message);
                }
            }
        }

        return View(model);
    }

How can I optimize it or implement the ASP.NET Identity in this? I read about Multi-Tenant but I'm not sure what it is.

I'm using FormsAuth right now and it works but seems to be very limited. For example, creating a user is difficult, however the Identity framework has the UserManager which is very helpful!

Clearly, I want something bulletproof to authenticate via DB or LDAP depending on the (bool)User.IsLdap property. I though about creating a small class that act like an "Auth Service" but I can't find a way to structure it and make it fast.

EDIT: I'm aware of External Providers for Identity but not sure if I can create my own with my LDAP Auth.

like image 225
Frederick Marcoux Avatar asked Jul 14 '15 16:07

Frederick Marcoux


1 Answers

Using ASP.NET Identity is the better way to go because it uses the OWIN stack instead of relying on system.web. This was done mostly for performance and seperation of concerns reasons. Also it's good to know that the newer versions of MVC are going this way.

What you are trying to do is use Mixed authentication of both Forms and Windows. While there are many ways to do this, often the easiest is to enable windows auth on the web server and then allow IIS to do the heavy lifting for you which would remove the need for the webservice. If that is the direction you want to go, you may want to have a look at this similar question that should get you headed in the right direction.

Mixed authentication for OWIN

Even if you don't do it exactly like the solution that is proposed, you would end up implementing your own OWIN middleware to do your authentication.

like image 106
Kevin Harker Avatar answered Nov 15 '22 19:11

Kevin Harker