Page 10 of 10

Afstand tussen twee GPS coordinaten berekenen

In alsmaar meer maatsoftware die we opleveren komt ergens wel de vraag “we willen een lijst van klanten/leveranciers in de buurt van …” Tot voor een tijdje werkten we daarom met een query op postcode (select * from tabel where postcode like ‘85%’).  Het gaf een vrij goed idee maar effectief gaan filteren op adressen die in een straal van X km rond een bepaald punt liggen is natuurlijk veel exacter.  Sinds kort hebben we dit in een aantal pakketten geïntegreerd; het berekenen van de afstand tussen twee punten is in principe vrij simpel.

 1: public Double GetDistance(Double[] from, Double[] to)
 2:  {
 3:      Double dLat1LnRad = from[0] * (Math.PI / 180.0);
 4:      Double dLong1LnRad = from[1] * (Math.PI / 180.0);
 5:      Double dLat2LnRad = to[0] * (Math.PI / 180.0);
 6:      Double dLong2LnRad = to[1] * (Math.PI / 180.0);
 7:
 8:      Double dLongitude = dLong2LnRad - dLong1LnRad;
 9:      Double dLatitude = dLat2LnRad - dLat1LnRad;
 10:
 11:      Double a = Math.Pow(Math.Sin(dLatitude / 2.0), 2.0) + Math.Cos(dLat1LnRad) * Math.Cos(dLat2LnRad) * Math.Pow(Math.Sin(dLongitude / 2.0), 2.0);
 12:      Double c = 2.0 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1.0 - a));
 13:
 14:      const Double kEarthRadiusKms = 6376.5;
 15:      return kEarthRadiusKms * c;
 16:  }

De moeilijkheid was om op een vlotte manier aan de juiste gps coordinaten te komen en dat is nu vrij simpel geworden dankzij Google Earth API.

 1: private const string _googleUri = "http://maps.google.com/maps/geo?q=";
 2: private const string _googleKey = "Get Your Own Free Google Key";
 3: private const string _outputType = "csv";
 4:
 5: public Double[] GetCoordinates(string address)
 6: {
 7:     address = HttpUtility.UrlEncode(address);
 8:     WebClient client = new WebClient();
 9:
 10:     string[] geocodeInfo = client.DownloadString(new Uri(String.Format("{0}{1}&output={2}&key={3}", _googleUri, address, _outputType, _googleKey))).ToString().Split(',');
 11:     Double lat = Convert.ToDouble(geocodeInfo[2].Replace(".", ","));
 12:     Double lon = Convert.ToDouble(geocodeInfo[3].Replace(".",","));
 13:     Double[] returnvalue = new Double[2];
 14:     returnvalue[0] = lat;
 15:     returnvalue[1] = lon;
 16:
 17:     return returnvalue;
 18: }

Als je nu wil weten welke adressen in een straal van 30 km rond je bedrijf liggen kan je dat eenvoudig berekenen door je eigen gps coordinaten op te vragen en dan alle adressen in je databank overlopen om te zien of ze verder of minder ver dan 30 km van je bedrijf verwijdert liggen. Voor kleine databanken is dat haalbaar voor grotere is het behalve CPU intensief ook IO intensief en het kan dus intelligenter.

Bepalen welke GPS coordinaten in een straal van x KM rond je bedrijf liggen is mogelijk maar onpraktisch, je zou in detail elk puntje op de cirkellijn moeten bijhouden en elk gps coordinaat van je contacten moeten afwegen bij de cirkellijn.  We zouden het moeten testen maar hoewel het intelligenter lijkt zou het waarschijnlijk meer belastend zijn voor de server dan de eerste oplossing.

We kozen ervoor een vierkant te tekenen waar onze cirkel net in kan. Op basis van de coordinaat links boven en die rechtsonder kunnen we een SQL commando schrijven die de adressen selecteert die in het vierkant zitten. We moeten dan enkel manueel nog de adressen in de paarse zone eruit filteren.

figuur

ASP.NET Impersonation voor Active Directory bewerkingen

Een tijdje geleden ontwikkelde ik een kleine Intranet toepassing waarmee gebruikers beperkte acties kunnen uitvoeren op de Active Directory.   Bij het programmeren ontstond intern al snel een discussie omtrent het veiligheidsaspect van deze applicatie.

De code voorziet oa. in de mogelijkheid om gebruikers aan te maken, die gebruikers toe te voegen aan groepen, het paswoord van een gebruiker te wijzigen (zonder het oude te kennen), enz … Als “iedereen” die code zou kunnen uitvoeren is er uiteraard sprake van een enorm veiligheidsprobleem. Uiteraard heeft Microsoft ervoor gezorgd dat dit niet kan. Enkel wie effectief het recht heeft om zo’n zaken te doen op Active Directory kan ook de code uitvoeren. Nu is de vraag “wie voert de code uit eenmaal ze binnen IIS draait?”.

In “the good old days” toen we nog volop aan de slag waren met classic ASP was het vrij eenvoudig. Wanneer een site vrij toegankelijk was (anonymous logon) werd code uitgevoerd door IUSR_Computername of IWAM_Computername. Als je je code toegang wou geven tot een bepaalde map/bestand volstond het om die gebruikers de gepaste toegang te geven. Het is overigens eenvoudig om dit gedrag te wijzigen. Bij het opvragen van de eigenschappen van een site, tabblad “Directory”, kan je zelf een gebruiker instellen die gebruikt wordt wanneer mensen “zomaar” toegang hebben tot je site. Stel je hier dus een administrator in, dan heeft je code quasi onbeperkte toegang tot je systeem.

Wanneer mensen moeten inloggen om je site/code te bezoeken wordt de code uitgevoerd met de rechten die de persoon heeft die aanmeldt.  Wanneer er niet aan fout opvolging gedaan wordt kan je dus een site hebben die in bepaalde situaties prima werkt (voldoende rechten om alles te doen) en diezelfde site die continue de mist in gaat (onvoldoende rechten om het nodige te doen).  Dit is wat we “impersonation” noemen.

In ASP.NET is het toch wel even anders. Als men niet moet inloggen om je website te bezoeken dan wordt je code uitgevoerd met de rechten van de “Identity” van de application pool waar je website in ondergebracht is. Als je moet inloggen om je website te bezoeken dan … wordt je code nog steeds uitgevoerd met de rechten van de “Identity” van de application pool waar je website in ondergebracht is. Impersonation werkt nooit in asp.net tenzij je er nadrukkelijk om vraagt. Nadrukkelijk … <identity impersonate=”true” /> toevoegen aan de system.Web sectie van je web.config volstaat.  Als men moet aanmelden om je site te bezoeken wordt je code uitgevoerd met de rechten van de aangemelde gebruiker. Eenvoudig, toch? Jammer, maar het is nog niet gedaan.

Wanneer de authenticatie van je website op NTLM gebaseerd is (bvb. Integrated Windows authentication) moet je rekening houden met de “one hop rule”.  De “one hop rule” is een trendy benaming voor het feit dat NTLM login gegevens niet kunnen doorgestuurd worden.  Dus concreet … zolang je code betrekking heeft op objecten binnen de webserver is er geen probleem (mappen op de webserver aanmaken bvb), je code wordt uitgevoerd met de rechten van de aangemelde gebruiker. Van zodra je code zaken wil gaan doen met objecten buiten de webserver (bvb. de SQL server, de domeincontroller, …) vervalt de impersonation en zal je code opnieuw uitgevoerd worden met de rechten van de “identity” van de application pool waar je website in ondergebracht is.

Misschien is dit gewenst gedrag, maar misschien ook niet. De “one hop rule” is niet van toepassing wanneer gebruikersnaam en paswoord worden meegegeven in de web.config => <identity impersonate=”true” userName=”domainuser” password=”xxx” /> in de system.Web sectie zorgt ervoor dat je code zoiezo wordt uitgevoerd met de rechten van de ingestelde gebruiker, ook als de website zonder login toegankelijk is en het maakt niet langer uit of je code nu iets doet op de webserver zelf of eender waar in het domein.  Het nadeel hier is dat de code een bepaalde hoeveelheid rechten krijgt ongeacht wie aangemeld is.  Je hebt niet de mogelijkheid te zeggen “als X aanmeldt, krijgt hij de rechten van X”. Wil je dit bekomen dan behoud je de eenvoudige impersonate code in web.config en schakel je over naar Kerberos gebaseerde authenticatie, die is immers ook niet onderhevig aan de “one hop rule”.