C# Enums - A bit of Extra Caution when working with Enums

By Anoop Madhusudanan

Vote on HN

Straight to a question for you.

Consider the following code, where you accept a caller key and a token request from a caller, to issue a security key for further requests? Note that we also have a minimal exclusion check, where we prevent certain callers from getting the admin permission. Now, the question. What is wrong with the code below?

public enum SecurityToken
    {
        Admin,
        Registered,
        Anon
    }

    public class SecurityGateway
    {
        public string GetSecurityKey(string callerKey,SecurityToken token)
        {

            //Prevent caller2 from getting the admin token
            if (callerKey.Equals("secretcallerkey2") 
                && token == SecurityToken.Admin)
                return "Error: You can't request an admin token";

            //Issue the token
            switch (token)
            {
                case SecurityToken.Anon:
                    return "PermissionKeyForAnonymous";
                case SecurityToken.Registered:
                    return "PermissionKeyForRegistered";
                default:
                    return "PermissionKeyForAdmin";
            }
        }
    }

If you already found the issue, you may stop reading here. Otherwise, let us examine this in a bit detail.

Assume that a caller, let us sayCaller1, is requesting a security key for leveraging admin permissions.

SecurityGateway gateway = new SecurityGateway();

            //Caller 1
            var key = gateway.GetSecurityKey("secretcallerkey1", SecurityToken.Admin);
            //key's value is PermissionKeyForAdmin for secretcallerkey1


As you may imagine, the value of key will be PermissionKeyForAdmin, as expected.

Now, the issue. As you may be aware, C# enums are implemented as integers by default, and you can cast integers to an enum type. So, if the Caller2 has some evil plans, it may do something like this.

SecurityGateway gateway = new SecurityGateway();

            //Caller 2
            var key = gateway.GetSecurityKey("secretcallerkey2", (SecurityToken)10);

            //OOps, key's value is still PermissionKeyForAdmin for secretcallerkey2, 
            //bypassing the exclusion check we've above
            


Note that I'm casting an integer to an enum, and the following exclusion check will be bypassed by Caller2, because the token's value is 10, instead of the value for SecurityToken.Admin.

//OOps, Caller2 can bypass this exclusion check

           //Prevent caller2 from getting the admin token
            if (callerKey.Equals("secretcallerkey2") 
                && token == SecurityToken.Admin)
                return "Error: You can't request an admin token";


Alright, so the point is, be a bit more careful when working with Enums in general, and also when you implement check conditions with enums.

Update: As Oleg pointed out below, an explicit check using Enum.IsDefined(..) to validate if the passed value exists in the specified enumeration is the best solution.


Happy coding, you may also love reading few more back to basic posts in this blog
© 2012. All Rights Reserved. Amazedsaint.com