Remotely Calling The Google Search Appliance RESTful Web Services When SAML is enabled

June 23rd, 2009

Calling the Google Search Appliance when a SAML interface or Forms Authentication security interface is enabled causes a bit of a challenge  from  SharePoint or ASP.NET.  The following is some code that we developed to handle all of the hand shaking from the redirects and cookie exchange.  This will be published shortly as a open source project.

public  string SecureSearch(string term)
        {
            try
            {
                StringBuilder defaultquery = new StringBuilder();
                defaultquery.Append(ConfigurationManager.AppSettings["GSADEVICEURL"]);
                defaultquery.Append("/search?q=" + term);
                defaultquery.Append("&client=" + ConfigurationManager.AppSettings["GSAFRONTEND"]);
                defaultquery.Append("&output=xml_no_dtd");
                defaultquery.Append("&site=" + ConfigurationManager.AppSettings["GSACOLLECTION"]);
                defaultquery.Append("&access=a");
                defaultquery.Append("&entqr=3&ud=1&oe=UTF-8&ie=UTF-8");
                defaultquery.Append("&filter=" + ConfigurationManager.AppSettings["GSASEARCHFILTER"]);
                defaultquery.Append("&num=" + ConfigurationManager.AppSettings["RESULTSPERPAGE"]);
               
                Regex cookieCheck = new Regex("googlecookiecheck", RegexOptions.IgnoreCase);

                log.Info("Step 1 Call GSA for secure query");
                string loginurl = callGSA(defaultquery.ToString(), false);

                //if the return url has the cookie check added, send the url back to the gsa
                //the cookie check cookie will be attached
                if (cookieCheck.Match(loginurl).Success)
                {
                    //send the url returned with cookiecheck back to GSA
                    log.Info("Step 2 Call GSA for secure doc, respond to cookiecheck request");
                    loginurl = callGSA(ConfigurationManager.AppSettings["GSADEVICEURL"] + loginurl, false);
                    if (!gsaResultsReturned)
                    {
                        log.Info("Step 3 Call GSA for secure only with redirect from cookiecheck request");
                        loginurl = callGSA(ConfigurationManager.AppSettings["GSADEVICEURL"] + loginurl, false);
                    }
                }

                if (!gsaResultsReturned)
                {
                    log.Info("Step 4 Call GSA to get result set");
                    loginurl = callGSA(loginurl, true);
                }
                log.Info("Step 5 COMPLETE");
               
               
            }
            catch (Exception ex)
            {
                log.Error("btnSearch_Click", ex);
            }

            return results.OuterXml.ToString();
        }

        private string callGSA(string url, bool allowredirect )
        {
            gsaResultsReturned = false;

            string returnURL = string.Empty;
            try
            {
                log.Error("callGSA() url ->" + url);
                HttpWebRequest HttpWReq = (HttpWebRequest)WebRequest.Create(url);
                HttpWReq.KeepAlive = true;
                HttpWReq.Accept = "*/*";
                HttpWReq.Headers.Add("Accept-Language", "en-us");
                HttpWReq.Headers.Add("Accept-Encoding", "gzip, deflate");
                HttpWReq.AllowAutoRedirect = allowredirect;
                HttpWReq.CookieContainer = cookieC;
                HttpWReq.Credentials = System.Net.CredentialCache.DefaultCredentials;
                HttpWReq.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; InfoPath.1; .NET CLR 2.0.50727)";
                if (allowredirect)
                {
                    HttpWReq.MaximumAutomaticRedirections = 10;
                }

                CookieCollection mycookies = HttpWReq.CookieContainer.GetCookies(new Uri(ConfigurationManager.AppSettings["GSACOOKIEURL"]));
               

                HttpWebResponse HttpWResp = (HttpWebResponse)HttpWReq.GetResponse();
                log.Info("......callGSA response http status = " + HttpWResp.StatusCode);
                //get header collection 
                WebHeaderCollection col = HttpWResp.Headers;
                if (HttpWResp.StatusCode.Equals(HttpStatusCode.Found))
                {
                    //get location and make request
                    string[] redirectURL = col.GetValues("Location");
                    returnURL = redirectURL[0];
                    log.Debug("......callGSA() found redirect URL from GSA to->" + redirectURL[0]);
                }
                //logHeader(col);
                CookieCollection csk = new CookieCollection();

                csk = HttpWResp.Cookies;
                for (int i = 0; i < csk.Count; i++)
                {
                    log.Debug("............. callGSA response cookies " + csk[i].Name + " value " + csk[i].Value);
                    log.Debug("............. callGSA response cook domain " + csk[i].Domain);
                    log.Debug("............. callGSA response cook Path " + csk[i].Path);
                    log.Debug("............. callGSA response cook expires " + csk[i].Expires.ToLongTimeString());
                    log.Debug("............. callGSA response cook secure " + csk[i].Secure.ToString());

                    String[] values = col.GetValues("Set-Cookie");
                    if (null != values && values.Length > 0)
                    {
                        for (int j = 0; j < values.Length; j++)
                        {
                            Uri cookuri = new UriBuilder("http", csk[i].Domain, 80).Uri;
                            log.Info("......callGSA moving cookie " + cookuri.ToString() + " " + values[j]);
                            cookieC.SetCookies(cookuri, values[j]);
                        }
                    }
                }

                //this is the final step, we have a result set from the GSA
                if (HttpWResp.StatusCode.Equals(HttpStatusCode.OK) ||
                    (returnURL.Equals(string.Empty)))
                {
                    gsaResultsReturned = true;
                    Stream receiveStream = HttpWResp.GetResponseStream();
                    Encoding UTF8_Encoding = System.Text.Encoding.GetEncoding("utf-8");
                    StreamReader readStream = new StreamReader(receiveStream, UTF8_Encoding);
                    //get the response and display
                    results.LoadXml(readStream.ReadToEnd());
                   
                }
            }
            catch (Exception ex)
            {
                log.Error("CallGSA ", ex);
            }

            return returnURL;
        }

Leave a Reply