Wednesday, July 2, 2014

RODC install issues

In certain areas of your expanded perimeter, installing an RODC has good security benefit.  There are some issues that can occur when installing an RODC.  It mostly has to do with the way AD works, but it is important to note.

Issue 1)  Don't create the site before you add the DC.

In a recent RODC setup, we decided to "jump the gun" and add the site to sites and services before setting up the RODC.  The problem with this is that you have to log in as a domain admin before you can promote a server.  This act causes AD to pick a DC from the next closest site (since the site you setup doesn't have one yet) and add it's DNS records to the site.  Once this is done, you are at the mercy of AD weights and priorities to determine which logon server you will use. 

This article has more detail on the AD Locator process. The solution is to go through DNS and delete the appropriate records for the incorrect DC.   

Issue 2)  Be mindful of which passwords are allowed to replicate

Only passwords that are explicitly allowed and not explicitly denied are allowed to replicate.  By default, the policy is quite restrictive, and with good reason.  You are probably deploying an RODC in a semi-trusted segment.  You probably don't want your schema admin password to be cached out there.  There are tools built in to AD to help you figure out who is authenticated to the RODC, and to allow you to test a user to see if the password would allowed to be cached.  You can also pre-populate passwords.  This is all done via the AD user and computers snap-in.

Issue 3)  Configuring Site Link Costs

Remember to change the costs of the site links!  If you want AD to always choose your RODC (unless it is unavailable), configure the site link cost appropriately. 

Issue 4)  Cached DC

Once the DC Locator process runs, the result is cached on the machine.  If you run into any of issues 1/2/3, you may be authenticating against the wrong DC.  Fixing the issue at the server level doesn't solve the problem because the result is already cached.

You can check to see what DC is cached using the nltest command.  You may have to copy the executable from a DC to a non-dc machine.

nltest /DSGetDC:<domain name>

To update the result, you can use

nltest /DSGetDC:<domain name> /FORCE

Issue 5) Use Azure data disks for the AD DS files

This issue is Azure specific, but probably a good location where you would want to deploy an RODC. 

See this article

Although you shouldn't have an issue when you deploy an RODC, it is good to follow the best practices outlined.



Monday, June 23, 2014

Azure and Multi Factor Authentication

In light of recent management console attacks (ie: codespaces) I wanted to detail out some steps to enable two factor authentication on the azure management portal.

First off all, there are 2 types of accounts @ Microsoft.  Organizational ones, and personal ones.  For example, my MSDN account is registered under an email address that actually belongs to the "personal" side, even though it is a corporate account.

In order to enable two factor authentication on a personal account, visit this link and sign in. Under the Security & Password tab, you will see the following section:


As you can tell from the screenshot above, I have already enabled two factor authentication.  You will see a message in that space that asks you to enable two factor authentication.  Follow the steps.  On Andriod devices (or "other" in Microsoft vernacular) it ties in with the authenticator app which is the same app used for google services.

Organizational accounts are different beasts, and tied to the Windows Azure Active Directory (WAAD).  Inside my MSDN account, I have setup a default WAAD.  I have also tied that to my personal domain (shamirc.com).  I can now create users inside that WAAD instance and assign them different roles for the AD.  I can also add them as an administrator on my subscription.  Pretty neat!

The first thing you need to do for organizational accounts such as the one described above is setup a multi-factor authentication provider.  Details can be found here.  After this is complete, you need to enable multi-factor authentication for a particular user inside the directory.


As you can see on the waaaay bottom of this screenshot, after I've entered my directory, there is a "manage multi-factor authentication" button.  Click on that an you will be taken to a screen where you can enable MFA for selected users.  Find the user(s) that you want, and click enable.

The next time the user logs into any Microsoft site, they will see the following after they type in their password.

Follow the instructions and you are now all setup! 

For reference, the official MS docs can be found here.

Thursday, May 8, 2014

Hacky In Memory User Store for ASP.NET Identity 2.0

There are cases when you want to build out a sample ASP.NET Web project (MVC in this case) just to test something out.  I personally hate the defaults that come with most .net mvc projects.  It forces you to create a database, initialize that database, and other useless steps.  Furthermore, I hate working from the predefined templates that come with MVC.  I like that you can get a working app quickly, but it really doesn't help you understand exactly what is going on.

In previous versions of MVC, you would just create a custom membership provider, override a few methods, register it in the web.config and you were off.  Identity 2.0 changed all of that.

In this post I will try and outline what steps I took to create an in memory user store with very limited functionality.  Bear in mind the goal of this article is to get you going in the right direction, and is probably not a complete solution.

The first thing you are going to want to do is read a couple of MS articles to get a good base line.

Adding Identity 2.0 to an empty project
Overview of Custom Storage Providers for ASP.NET Identity

There are a couple of key components here.  The first in managers.  There are built in managers, which are easy enough to use.  The problem is that there is no source code released for the Microsoft.AspNet.Identity, so it is hard to see exactly what the built in user manager does.  It obviously has to interface with the authorization/authentication framework in MVC, but little detail on that has been released.

The second component is the "stores".  Instead of having one big store (or two as in MVC4) they have broken up the stores into various interfaces.  Each store adds a certain amount of functionality to the user store.  It is understood that the manager knows what type of "store" it has received and which interfaces are implemented.  Based on these interfaces, different methods are called and different functionality is available.

The first step in this process is to create an user object.  At a minimum, this user object must implement IUser which only requires a string id and string password.


    public class IdentityUser : IUser
    {
        public IdentityUser(string id, string userName, string hashedPassword)
        {
            Id = id;
            UserName = userName;
            this.hashedPassword = hashedPassword;
        }

        public IdentityUser(string userName)
        {
            UserName = userName;
        }

        public string Id { get; private set; }
        public string UserName { get; set; }
        public string hashedPassword { get; set; }
    }

In the implementation above, I am adding hashedPassword to the object.  You can add any fields you like.  This is probably a hack and probably not the right place to add it, but I am just trying to get something up quickly.

After the user object is created, you need to create a store.  Depending on the features you want to implement, you will implement different interfaces.  See the links above for more.


    public class InMemoryUserStore : IUserStore<identityuser>, IUserPasswordStore<identityuser>
    {
        private IList<identityuser> userList = new List<identityuser>();

        public InMemoryUserStore()
        {
            userList.Add(new IdentityUser("1", "admin", Crypto.HashPassword("admin")));
        }

        public void Dispose()
        {
            
        }

        public Task CreateAsync(IdentityUser user)
        {
            throw new NotImplementedException();
        }

        public Task UpdateAsync(IdentityUser user)
        {
            throw new NotImplementedException();
        }

        public Task DeleteAsync(IdentityUser user)
        {
            throw new NotImplementedException();
        }

        public Task<identityuser> FindByIdAsync(string userId)
        {
            return Task.FromResult(userList.FirstOrDefault(x => x.Id.Equals(userId)));
        }

        public Task<identityuser> FindByNameAsync(string userName)
        {
            return Task.FromResult(userList.FirstOrDefault(x => x.UserName.Equals(userName)));
        }

        public Task SetPasswordHashAsync(IdentityUser user, string passwordHash)
        {
            throw new NotImplementedException();
        }

        public Task<string> GetPasswordHashAsync(IdentityUser user)
        {
            return Task.FromResult(userList.First(x => x.UserName.Equals(user.UserName)).hashedPassword);
        }

        public Task<bool> HasPasswordAsync(IdentityUser user)
        {
            var appUser = userList.FirstOrDefault(x => x.UserName.Equals(user.UserName));
            if (appUser == null)
            {
                return Task.FromResult(false);
            }

            return Task.FromResult(!String.IsNullOrEmpty(appUser.hashedPassword));
        }
    }

As you can see from above, I only implemented a few of the methods.  I'm not worried about registration, or edit functionality.  I just need to create an account to login with that plugs in with the built in authentication and authorization frameworks.  As you can see from above, I initialize the user in the constructor. 

After this is done, you can just initialize the user manager and pass it the store that you have created.


    [Authorize]
    public class BaseController: Controller
    {
        public BaseController() : this(new UserManager<identityuser>(new InMemoryUserStore()))
        {
            
        }

        private BaseController(UserManager<identityuser> userManager)
        {
            UserManager = userManager;
        }

        public UserManager<identityuser> UserManager { get; private set; }

        protected IAuthenticationManager AuthenticationManager
        {
            get { return HttpContext.GetOwinContext().Authentication; }
        }
 
    }

After this, you have to actually log the user in using the OWIN providers.  You can see samples of this on the internet or if you create a MVC app template with authentication enabled.

Hope that helps!