예제 #1
0
        public void TestOTPDefault()
        {
            string[] otps    = new string[NB_OTP];
            string[] otpRefs = new string[] {
                "78872199", "07062011", "22261770", "63968432", "18394668",
                "27476910", "64078108", "27055128", "61637484", "72423775"
            };

            OTP otp = new OTP();

            otps[0] = otp.GetCurrentOTP();
            Assert.AreEqual(otpRefs[0], otps[0]);

            for (int n = 1; n < NB_OTP; n++)
            {
                otps[n] = otp.GetNextOTP();
                Assert.AreEqual(otpRefs[n], otps[n]);
            }
        }
예제 #2
0
        public void TestOTPCustom()
        {
            string[] otps    = new string[NB_OTP];
            string[] otpRefs = new string[] {
                "77150324", "35347368", "80798457", "80798457", "86323714",
                "72722788", "24190050", "32111478", "01733054", "59344564"
            };
            byte[] secretKey = new byte[SECRET_LENGTH]
            {
                0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43,
                0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
            };

            OTP otp = new OTP(secretKey: secretKey);

            otps[0] = otp.GetCurrentOTP();

            for (int n = 1; n < NB_OTP; n++)
            {
                otps[n] = otp.GetNextOTP();
            }
        }
        /// <summary>
        /// Validate if OTP in header is acceptable. This routine could use some refactoring.
        /// </summary>
        /// <param name="headers">HttpHeaders from HttpRequestMessage</param>
        /// <returns>true if acceptable, false otherwise</returns>
        private bool ValidateOTP(HttpHeaders headers)
        {
            bool result = false;

            // in a "real" system, we'd go to a user database to get a key corresponding with the Id we've already validated
            byte[] secretKey = proxy.Controllers.Utility.ConvertToByteArray(ConfigurationManager.AppSettings["OTPKey"]);

            try
            {
                IEnumerable <string> headerValues = headers.GetValues("key");
                var incomingOTP = headerValues.FirstOrDefault();

                // for the sake of sanity in testing...I allow myself to define a static value for
                // the OTP that will always validate successfully. :/ I'm queasy just writing this comment.
                if (!String.IsNullOrEmpty(ConfigurationManager.AppSettings["expectedOTP"]))
                {
                    if (ConfigurationManager.AppSettings["expectedOTP"].Equals(incomingOTP))
                    {
                        result = true;
                    }
                }
                else
                {
                    // Calculate what the key should be, compare it what we got in the header
                    string expectedOTP = OTP.GetOTP(secretKey);
                    telemetry.TrackTrace("Incoming key is " + incomingOTP + ", Expected key is " + expectedOTP);
                    if (expectedOTP.Equals(incomingOTP))
                    {
                        telemetry.TrackTrace("Key in header is valid.");
                        result = true;
                    }
                    else
                    {
                        expectedOTP = OTP.GetLastOTP(secretKey);
                        telemetry.TrackTrace("Incoming key is " + incomingOTP + ", Prior key is " + expectedOTP);
                        if (expectedOTP.Equals(incomingOTP))
                        {
                            telemetry.TrackTrace("Prior key matches, key considered to be valid.");
                            result = true;
                        }
                        else
                        {
                            expectedOTP = OTP.GetNextOTP(secretKey);
                            telemetry.TrackTrace("Incoming key is " + incomingOTP + ", Next key is " + expectedOTP);
                            if (expectedOTP.Equals(incomingOTP))
                            {
                                telemetry.TrackTrace("Next key matches, key considered to be valid");
                                result = true;
                            }
                            else
                            {
                                telemetry.TrackTrace("Key in header is not valid.");
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                telemetry.TrackTrace("Exception when validating key in header: " + ex.Message);
                result = false;
            }

            return(result);
            // NOTE: In our design, we'd never expect more than one request per 30 second OTP window.
            // Given that, we should never allow a given OTP key to be matched twice within
            // Now() +/- 30 seconds, assuming the OTP algorithn would never generate a sequence of keys
            // in which a key repeated within a 3-window range. So, we *should* be keeping track and
            // noting what key values have been matched in the last few requests, disallowing any
            // repeated matches. That's just complexity I don't care about for my uses here so not
            // pursuing it. Caring at that level would imply we also care about rate-limiting requests, etc.
            // to defeat brute-force auth attempts. This project is a hobby, not a job.
        }