using System; using System.Data; using System.Text; using System.Text.RegularExpressions; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Reflection; using System.Collections.Specialized; using System.Xml; using umbraco; using umbraco.cms.businesslogic.member; namespace presentation.umbracoBase { public class requestModule : IHttpModule { #region IHttpModule Members public void Dispose() { throw new Exception("The method or operation is not implemented."); } public void Init(HttpApplication httpApp) { httpApp.BeginRequest += new EventHandler(OnBeginRequest); } public void OnBeginRequest(Object sender, EventArgs e) { HttpApplication httpApp = (HttpApplication)sender; //remove extension and split the url object[] urlArray = httpApp.Context.Request.RawUrl.Replace(".aspx", "").Split('/'); if (urlArray[1].ToString() == "base") { //There has to be minimum 4 parts in the url for this to work... /base/library/method/[parameter].aspx if (urlArray.Length >= 4) { string extensionAlias = urlArray[2].ToString(); string methodName = urlArray[3].ToString(); httpApp.Response.ContentType = "text/xml"; MyMethodStruct myMMS = getMethod(extensionAlias, methodName); if (myMMS.isAllowed) { httpApp.Response.Output.Write(invokeMethod(myMMS, urlArray)); } else { //Very static error msg... httpApp.Response.Output.Write("Extension not found or permission denied"); } //end the resposne httpApp.Response.End(); } } } private string invokeMethod(MyMethodStruct myMethod, object[] paras) { try { //So method is either not found or not valid... this should probably be moved... if (!myMethod.method.IsPublic || !myMethod.method.IsStatic) return "Method has to be public and static"; else //And if it is lets continue trying to invoke it... { //lets check if we have parameters enough in the url.. if (myMethod.method.GetParameters().Length > (paras.Length - 4)) //Too few return "Not Enough parameters in url"; else { //We have enough parameters... lets invoke.. //Create an instance of the type we need to invoke the method from. Object obj = Activator.CreateInstance(myMethod.type); Object response; //umbracoBase.baseBinder bBinder = new baseBinder(); if (myMethod.method.GetParameters().Length == 0) { //response = myMethod.method.Invoke(obj, BindingFlags.Public | BindingFlags.Instance, bBinder, null, System.Globalization.CultureInfo.CurrentCulture); response = myMethod.method.Invoke(obj, null); //Invoke with null as parameters as there are none } else { //We only need the parts of the url above the number 4 so we'll //recast those to objects and add them to the object[] //Getting the right lenght.. 4 is the magic number dum di dum.. object[] methodParams = new object[(paras.Length - 4)]; int i = 0; foreach (ParameterInfo pInfo in myMethod.method.GetParameters()) { Type myType = Type.GetType(pInfo.ParameterType.ToString()); methodParams[(i)] = Convert.ChangeType(paras[i + 4], myType); i++; } //Invoke with methodParams //response = myMethod.method.Invoke(obj, BindingFlags.Public | BindingFlags.Instance, bBinder, methodParams, System.Globalization.CultureInfo.CurrentCulture); response = myMethod.method.Invoke(obj, methodParams); } /*TODO - SOMETHING ALITTLE BETTER THEN ONLY CHECK FOR XPATHNODEITERATOR OR ELSE do ToString() */ if (response != null) { if (myMethod.method.ReturnType.ToString() == "System.Xml.XPath.XPathNodeIterator") return ((System.Xml.XPath.XPathNodeIterator)response).Current.OuterXml; else { string strResponse = ((string)response.ToString()); //do a quick "is this html?" check... if it is add CDATA... if (strResponse.Contains("<") || strResponse.Contains(">")) strResponse = ""; return "" + strResponse + ""; } } else { //Error msg... return "Null value returned"; } } } } catch (Exception ex) { //Overall exception handling... return ""; } } private struct MyMethodStruct { public Type type; public MethodInfo method; public Assembly assembly; public string alias; public bool isAllowed; } private static MyMethodStruct getMethod(string extensionAlias, string methodName) { bool allowed = false; XmlDocument baseDoc = new XmlDocument(); //RESTExtension document... baseDoc.Load(System.Web.HttpContext.Current.Server.MapPath(GlobalSettings.Path + "/../config/restExtensions.xml")); XmlNode baseExt = baseDoc.SelectSingleNode("/RestExtensions/ext [@alias='" + extensionAlias + "']/permission [@method='" + methodName + "']"); //basicly - if not there.. it's not allowed... if (baseExt != null) { //Access for all ? if (baseExt.Attributes["allowAll"] != null) { if (baseExt.Attributes["allowAll"].Value.ToString().ToLower() == "true") allowed = true; } if (!allowed) { //Member Based permissions.. check for group, type and ID... Member currentMem = library.library.GetCurrentMember(); // <-- /TODO/ uses bases own member class as umbracos doesn't work yet... //not basic.. and not logged in? - out.. if (currentMem == null) { allowed = false; } else //do member authentication stuff... allowed = memberAuthentication(baseExt, currentMem); } } if (allowed) { XmlNode extNode = baseDoc.SelectSingleNode("/RestExtensions/ext [@alias='" + extensionAlias + "']"); string asml = extNode.Attributes["assembly"].Value; string assemblyPath = System.Web.HttpContext.Current.Server.MapPath(GlobalSettings.Path + "/.." + asml + ".dll"); Assembly returnAssembly = System.Reflection.Assembly.LoadFrom(assemblyPath); string returnTypeName = extNode.Attributes["type"].Value; Type returnType = returnAssembly.GetType(returnTypeName); MyMethodStruct mms = new MyMethodStruct(); mms.alias = extensionAlias; mms.assembly = returnAssembly; mms.method = returnType.GetMethod(methodName); mms.type = returnType; mms.isAllowed = true; return mms; } else { MyMethodStruct noMms = new MyMethodStruct(); noMms.isAllowed = false; return noMms; } } private static bool memberAuthentication(XmlNode baseExt, Member currentMem) { //Check group, type and ID bool memberAccess = false; if (baseExt.Attributes["allowGroup"] != null) { if (baseExt.Attributes["allowGroup"].Value != "") { //Groups array string[] groupArray = baseExt.Attributes["allowGroup"].Value.Split(','); foreach (MemberGroup mg in currentMem.Groups.Values) { foreach (string group in groupArray) { if (group == mg.Text) memberAccess = true; } } } } //Membertype allowed? if (baseExt.Attributes["allowType"] != null && !memberAccess) { if (baseExt.Attributes["allowType"].Value != "") { //Types array string[] typeArray = baseExt.Attributes["allowType"].Value.Split(','); foreach (string type in typeArray) { if (type == currentMem.ContentType.Alias) memberAccess = true; } } } //Member ID allowed? should this work with loginName instead? if (baseExt.Attributes["allowMember"] != null && !memberAccess) { if (baseExt.Attributes["allowMember"].Value != "") { if (int.Parse((string)baseExt.Attributes["allowMember"].Value.Trim()) == currentMem.Id) memberAccess = true; } } return memberAccess; } #endregion } }