Пример #1
0
        protected override void Action()
        {
            base.Action();
            String guid = Request[PtaServerConstants.OURGUID_KEY];

            bboardDR = PtaUtil.GetBBoardDataReaderByGuid(guid);
            RequestValidator rv = new RequestValidator(bboardDR);

            rv.Validate(Request);
        }
        /// <summary>
        /// Standard entry point of IHttpHandler, main processing flow.
        /// </summary>
        public void ProcessRequest(HttpContext context)
        {
            log4net.ILog log = PtaUtil.getLog4netLogger(this.GetType().FullName + ".ProcessRequest(): ");
            try {
                this.context = context;
                String guid = context.Request.Form["ourguid"];
                bboardDR = PtaUtil.GetBBoardDataReaderByGuid(guid);
                onErrorServerTransfer = PtaUtil.GetDBReaderStringField(bboardDR, "OnErrorServerTransfer");
                RequestValidator rv = new RequestValidator(bboardDR);
                rv.Validate(context.Request);
                Redirect();
            } catch (System.Threading.ThreadAbortException) {
                //this is normal processing of Server.Transfer() and Response.End()
                throw;
            } catch (Exception e) {
                PtaUtil.LogExceptionAndFormParameters(log, e);
                //String on_err_st = onErrorServerTransfer;
                //if (on_err_st == null) on_err_st = PtaUtil.GetProxyWebFolder() + "ErrorPages/PtaDefaultErrPage.aspx";
                //context.Server.Transfer(on_err_st, true);
                String back_link = context.Request.Form["tcbaseurl"] + context.Request.Form["returnurl"];
                String err_page  = PtaUtil.GenerateSimpleErrorPage(back_link);
                context.Response.Write(err_page);
                log.Debug("onErrorServerTransfer: " + onErrorServerTransfer);
                if (onErrorServerTransfer != null)
                {
                    context.Server.Transfer(onErrorServerTransfer, true);
                }

                /*                else {
                 *                  back_link = context.Request.Form["tcbaseurl"] + context.Request.Form["returnurl"];
                 *                  context.Response.Write("Your request could not be processed. <br/>");
                 *                  context.Response.Write("Back to Blackboard: " + "<a href=\"" + back_link + "\">" + back_link + "</a><br/>");
                 *              }*/

                //throw;
            } finally {
                PtaUtil.CloseDataReader(drParam);
                PtaUtil.CloseDataReader(drMenuLink);
                PtaUtil.CloseDataReader(bboardDR);
            }
        }
Пример #3
0
        /// <summary>
        /// Performs series of actions necessary for validation of passed by Blackboard parameters.
        /// See http://www.edugarage.com/display/BBDN/Proxy+Tool+SSO , internal method comments and java client sample code for details.
        /// Performs periodical cleanup of collected nonces upon every NonceCleanupCount invocation
        /// </summary>
        public void Validate(HttpRequest request)
        {
            log4net.ILog log = PtaUtil.getLog4netLogger(this.GetType().FullName + ".Validate(): ");
            request.ContentEncoding = System.Text.Encoding.UTF8;


            if (bboardDR == null)
            {
                bboardDR = PtaUtil.GetBBoardDataReaderByGuid(guid);
            }

            String s_secret = PtaUtil.GetDBReaderStringField(bboardDR, "SharedSecret");

            //http://www.edugarage.com/display/BBDN/Proxy+Tool+SSO
            // 1. Sort the posted data based on the key names and then concatenate all of the values together in the sorted order
            String[] sorted_form_keys = request.Form.AllKeys;
            Array.Sort(sorted_form_keys);
            System.Text.StringBuilder data_string = new System.Text.StringBuilder("");
            foreach (String form_key in sorted_form_keys)
            {
                /* from proxy\java\src\com\blackboard\test\proxy\GenericParameters.java:
                 * // ignore extra parameters added after the mac was generated/set
                 *  if ( key.startsWith( "top_" ) || key.startsWith( "bottom_" ) )
                 *      {
                 *          //ignore
                 *      }
                 * */
                if (form_key.StartsWith("top_", StringComparison.OrdinalIgnoreCase) ||
                    form_key.StartsWith("bottom_", StringComparison.OrdinalIgnoreCase)
                    //MAC cannot be calculated over itself
                    || form_key.Equals("mac", StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }
                data_string.Append(request.Form[form_key]);
            }
            log.Debug("data_string: " + data_string);
            // 2. append the shared secret
            data_string.Append(s_secret);
            // 3. Turn this string into a string of utf-8 bytes
            byte[] data_buffer = System.Text.Encoding.UTF8.GetBytes(data_string.ToString());
            // 4. Create a message digest from these bytes
            System.Security.Cryptography.MD5 md = new System.Security.Cryptography.MD5CryptoServiceProvider();
            byte[] md5_hash = md.ComputeHash(data_buffer);
            // 5. Convert the resulting byte array into a base64 encoded string
            String md5_hash_64 = System.Convert.ToBase64String(md5_hash);

            log.Debug("md5_hash_64: " + md5_hash_64);
            //relace operations below are copied from proxy\java\src\com\blackboard\test\proxy\ProxyUtil.java  generateMac()
            md5_hash_64.Replace("\r", "");
            md5_hash_64.Replace("\n", "");
            log.Debug("md5_hash_64: " + md5_hash_64);

            String bb_mac = request.Form[PtaServerConstants.MAC_KEY];

            log.Debug("bb_mac: " + bb_mac);

            //compare received and calculated MACs
            if (!bb_mac.Equals(md5_hash_64))
            {
                throw new PtaException("MAC mismatch. md5_hash_64: " + md5_hash_64 + "; bb_mac: " + bb_mac);
            }

            //check that timestamp is expected timeframe
            String bb_ts     = request.Form[PtaServerConstants.TIMESTAMP_KEY];
            long   bb_millis = Int64.Parse(bb_ts);

            log.Debug("bb_millis: " + bb_millis);

            long mac_life_ms = Int64.Parse(WebConfigurationManager.AppSettings["MacLifetimeInMinutes"]);

            log.Debug("mac_life_ms: " + mac_life_ms);
            long mac_life_millis = mac_life_ms * 1000 * 60;

            //http://bytes.com/topic/c-sharp/answers/557734-java-system-currenttimemillis-equivalent
            //- about java System.currentTimeMillis() in .net
            DateTime utc_now = DateTime.UtcNow;

            log.Debug("utc_now: " + utc_now);
            DateTime base_time = new DateTime(1970, 1, 1, 0, 0, 0);

            log.Debug("base_time: " + base_time);
            long proxy_millis = (utc_now - base_time).Ticks / 10000;

            log.Debug("proxy_millis: " + proxy_millis);

            if (Math.Abs(proxy_millis - bb_millis) > mac_life_millis)   //added abs() - not to be much earlier too. Assuming that earlier timestamp may be possible due to non-synchronized system time on BB and proxy server
            {
                throw new PtaException("Timestamp is out of max request delay. proxy_millis(secs): " + proxy_millis + "(" + proxy_millis / 1000 + "); bb_millis(secs): " + bb_millis + "(" + bb_millis / 1000 + "); mac_life_ms(secs): " + mac_life_millis + "(" + mac_life_millis / 1000 + ")");
            }

            String nonce = request.Form[PtaServerConstants.NONCE_KEY];

            if (nonce == null)
            {
                throw new PtaException("Invalid null Nonce");
            }
            if (RequestValidator.knownNonces.Contains(nonce))
            {
                throw new PtaException("Invalid duplicated Nonce. nonce: " + nonce);
            }
            int nonce_cleanup_count = Int16.Parse(WebConfigurationManager.AppSettings["NonceCleanupCount"]);

            lock (typeof(RequestValidator)) {
                knownNonces.Add(nonce, proxy_millis);
                nonceCleanupCounter++;

                if (nonceCleanupCounter > nonce_cleanup_count)
                {
                    //!! test/debug
                    Hashtable non_expired_nonces = new Hashtable();
                    foreach (DictionaryEntry nonce_de in RequestValidator.knownNonces)
                    {
                        long nonce_millis = (long)nonce_de.Value;
                        if (nonce_millis >= proxy_millis - mac_life_millis)
                        {
                            non_expired_nonces.Add(nonce_de.Key, nonce_millis);
                        }
                    }
                    knownNonces         = non_expired_nonces;
                    nonceCleanupCounter = 0;
                }
            }
        }