Durante la semana pasada he estado realizando una pequeña POC para el acceso a OWA (Outloook Web Access) via OwaAuth.dll y creo que, en cierto modo, estoy en la necesidad de que no pase al olvido, (si Juan, por si acaso, jejeje…).

¿Que es eso de OwaAuth.dll?

Se trata de la ISAPI de Exchange para el Logon en Owa. Esta es quizás una gran desconocida para muchos y aunque pasa desapercibida puede ser que en alguna ocasión sea necesario tener que hacer uso de ella para un propósito "un tanto distinto"😀.

 

Owa necesita un "sessionid" y un "cadata" para poder acceder y obtener información de cada una de sus páginas, pues bien, owaauth.dll es la encargada de obtener estos dos datos en una primera petición http de tipo POST, y, a partir de aquí, haciendo uso de estos en las peticiones sucesivas cada página web de Owa retornará el código HTML sin ningún tipo de preámbulo.

Paso a paso:

  • Invocar a owaauth.dll mediante una petición http (POST) a través de la url: "https://MACHINE_NAME/owa/auth/owaauth.dll" y con una serie de parámetros específicos; destination, flags, forcedownlevel, trusted, username, password, submitCreds, isUtf8. Para la obtención de estos parámetros he utilizado el siguiente método:
public string GetPostData(Uri uri) { // Setting data to create a request body. Dictionary<string, string> props = new Dictionary<string, string>(); props.Add("destination", uri.Scheme + Uri.SchemeDelimiter + HttpUtility.UrlEncode(uri.Host + "/exchange/" + _user + "/")); props.Add("flags", "4"); /* 0 */ props.Add("forcedownlevel", "0"); props.Add("trusted", "4"); /* 0 */ props.Add("username", HttpUtility.UrlEncode(String.Format(@"{0}\{1}", _domain, _user))); props.Add("password", HttpUtility.UrlEncode(_password)); props.Add("submitCreds", "Log+On"); props.Add("isUtf8", "1"); ASCIIEncoding encoding = new ASCIIEncoding(); string postData = String.Empty; foreach (string key in props.Keys) { string pValue = null; props.TryGetValue(key, out pValue); postData += string.Format("{0}={1}&", key, pValue); } if (props.Keys.Count > 0) postData = postData.Substring(0, postData.Length - 1); return postData; }
  • Realizada la petición HTTP según el siguiente método, se obtienen los datos buscados; "sessionid" y "cadata". Estos son recuperados en el objeto "CookieCollection".
public CookieCollection Authenticate(string url) { string postData = GetPostData(new Uri(url)); // Get Response - Cookie var response = HttpManager.SendRequest( url, postData, null, RequestMethod.POST, _user, _password, _domain, "application/x-www-form-urlencoded"); if (response.Cookies.Count < 2) return null; return response.Cookies; }
  • Ahora ya se pueden realizar peticiones a cualquiera de las páginas de Owa, eso sí, de tipo GET y teniendo en cuenta que deben ir acompañadas de "sessionid" y "cadata".
  • La respuesta a cada petición contiene el código HTML de cada una de las páginas solicitadas.

 

El método "SendRequest" es el encargado de realizar:

  1. La primera petición de tipo "POST" y contentType "application/x-www-form-urlencoded" y,
  2. Cada petición de tipo "GET" y contentType "text/xml".
public static HttpWebResponse SendRequest(string url, string postData, CookieCollection cookieCol, RequestMethod requestMethod, string user, string pwd, string domain, string contentType) { ServicePointManager.ServerCertificateValidationCallback = delegate(Object obj, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors) { return true; }; Uri uri = new Uri(url); var request = (HttpWebRequest)HttpWebRequest.Create(uri); request.Method = requestMethod.ToString(); request.CookieContainer = new CookieContainer(); request.ContentType = contentType; request.AllowAutoRedirect = false; // request.ServicePoint.Expect100Continue = false; request.KeepAlive = true; request.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1;" + ".NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)"; request.Accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg," + "application/x-ms-application, application/x-ms-xbap, application/vnd.ms-xpsdocument, application/xaml+xml, */*"; byte[] body = null; if (requestMethod == RequestMethod.POST) { // BODY body = Encoding.ASCII.GetBytes(postData); request.ContentLength = body.Length; } // Cookies if (cookieCol != null) { foreach (Cookie c in cookieCol) // request.Headers.Add(c.Name, c.Value); request.CookieContainer.Add(c); } // Security CredentialCache credentialCache = new System.Net.CredentialCache(); credentialCache.Add(uri, "Basic", /* Basic */ new System.Net.NetworkCredential(user, pwd, domain) ); request.Credentials = credentialCache; if (requestMethod == RequestMethod.POST) { // Response var stream = request.GetRequestStream(); stream.Write(body, 0, body.Length); stream.Close(); } return (HttpWebResponse)request.GetResponse(); }

Esto ha sido todo por esta vez, espero como siempre,  haber dado un pasito más.

Saludos @SundayHome

Juanlu

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }