kolmapäev, 29. juuli 2009

Sys.Net.WebRequest klassiga kliendi sertifikaadi küsimine kasutades Request.ClientCertificate meetodit

Vaja lisada andmete sisestusvormile nupp, millega saab osa vormil nõutavaid andmeid lugeda ID-kaardi pealt, kuid nii, et vormi teistele väljadele sisestatud info jääks peale ID-kaardilt andmete lugemist alles(ei tee tervele lehele Postbacki). See asi on võimalik lahendada .NET 3.5 AJAX-i Sys.Net.WebRequest klassi kasutades

Vorm näiteks selline, kus isikukoodi, ees- ja perekonnanime võib lugeda ID-kaardi pealt ja muu info tuleb käsitsi sisestada



ID-kaardilt saame andmed kätte tehes algselt lehelt WebRequest.invoke() GET requesti päringu lehele Idkaart.aspx, kus Request.ClientCertificate meetodiga loeme
ID-kaardilt andmed ja saadame nad tagasi püstkriipsuga eraldatud stringijadana Response.Write("Isikukood|Perekonnanimi|Eesnimi");
IIS-i poolt tuleb Idkaart.aspx lehel peale seada, et Accept Client certificate, siis pöördumisel
Idkaart.aspx poole küsitakse kliendi sertifikaati, ehk ID-kaardi puhul tuleb PIN1 sisestada

NB! Kui kasutatakse Sertifitseerimiskeskuse serte, siis nii JUUR-SK kui ka KLASS3-SK serdid peavad olema õieti paigaldatud, vastasel juhul Request.ClientCertificate ei pruugi tööle hakata

Idkaart.aspx lehe sisu selline, sealt loeme ID-kaardi andmed

public partial class IdKaart : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string inf="";
try
{
//küsime kliendi sertifikaati
HttpClientCertificate sert = Request.ClientCertificate;
if (sert.IsPresent) //kui sertifikaat on olemas
{
if (System.DateTime.Now < sert.ValidUntil) //kas kehtib veel
{
String unparsed = sert.Subject;
System.Text.RegularExpressions.Regex re = new Regex("SERIALNUMBER=(\\d{11})");
if (re.IsMatch(unparsed))
{
if (re.Match(unparsed).Groups[1].Value.Length == 11) //isikukood peab olema 11 sümbolit pikk
{
inf = re.Match(unparsed).Groups[1].Value + "|"; //isikukood
}
}
System.Text.RegularExpressions.Regex rename = new Regex("SN=(.*?),\\s+G=(.*?),");
if (rename.IsMatch(unparsed))
{
inf += rename.Match(unparsed).Groups[1].Value+"|"; //perekonnanimi
inf += rename.Match(unparsed).Groups[2].Value; //eesnimi
}
}
}
}
catch (SystemException ex)
{ }
//tagastame eraldatud stringijada isikukood|perekonnanimi|eesnimi
Response.Clear();
Response.BufferOutput = false;
Response.ContentType = "text/plain";
Response.ContentEncoding = System.Text.ASCIIEncoding.Default;
Response.Write(inf);
Response.End();
}
}

leht XMLHttpParing.aspx, kus andmeid küsime näeb välja selline, kasutada tuleb Javaskripti, mis WebRequest.invoke() meetodiga pöördub lehelt IdKaart.aspx andmeid lugema ja kui on sealt
andmed kätte saanud, siis täidab osad sisestusväljad ära ja keelab nende edasise kasutamine


<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="XMLHttpParing.aspx.cs" Inherits="ASP_DEMO.XMLHttpParing" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>XMLHttpPäring</title>
<script type="text/javascript">
var xmlreq;
function pagLoad() {
try {
var webRequest = new Sys.Net.WebRequest();
webRequest.set_url("IdKaart.aspx");
webRequest.set_httpVerb("GET");
webRequest.add_completed(completedHandler);
webRequest.invoke();
}
catch (err)
{ }
}
function completedHandler(result, eventArgs) {
if (result.get_responseAvailable()) {
var vastus = new Array();
vastus = result.get_responseData().split("|");
if (vastus.length == 3) {
var nimi = document.getElementById("<%= TextBoxPerenimi.ClientID %>");
nimi.value = vastus[1];
nimi.disabled = true; //kui tuleb andmeid ID-kaardilt, siis keelab edasise tekstivälja muutmise ära
nimi = document.getElementById("<%= TextBoxEesnimi.ClientID %>");
nimi.value = vastus[2];
nimi.disabled = true;
nimi = document.getElementById("<%= TextBoxIsikukood.ClientID %>");
nimi.value = vastus[0];
nimi.disabled = true;
nimi = document.getElementById("<%= ButtonIdkaart.ClientID %>");
nimi.disabled = true;
}
}
}
</script>

</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<asp:UpdatePanel runat="server" ID="UpdatePanel1">
<ContentTemplate>
<table>
<tr>
<td>Isikukood&nbsp;<asp:TextBox ID="TextBoxIsikukood" runat="server"></asp:TextBox></td>
</tr>
<tr>
<td>Perekonnanimi&nbsp;<asp:TextBox ID="TextBoxPerenimi" runat="server"></asp:TextBox></td>
</tr>
<tr>
<td>Eesnimi&nbsp;<asp:TextBox ID="TextBoxEesnimi" runat="server"></asp:TextBox></td>
</tr>
<tr>
<td style="width:200px">Muu info(tekst, mis ID kaardilt andmete küsimise järel jääb vormile alles<asp:TextBox ID="TextBoxMuu" MaxLength="400" Rows="4" Columns="70"
runat="server" TextMode="MultiLine"></asp:TextBox>
</td>
</tr>
</table>
<div>
<asp:Button ID="ButtonIdkaart" CausesValidation="false" runat="server"
Text="Loe andmed ID-kaardilt" />
<asp:Button ID="ButtonEdasi" runat="server" Text="Edasi" />
</div>
</ContentTemplate>
</asp:UpdatePanel>

</form>
</body>
</html>


code-behind XMLHttpParing.aspx lehele
public partial class XMLHttpParing : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//paneme kliendi poolse javascripti külge, tuleb kasutada return pagLoad(),
// kui ainult pagLoad() onClick eventile külge panna, teeb leht Postbacki ja
// webRequest.invoke()-iga loetud andmed korra vilksatavad ekraanil ja siis kaovad
this.ButtonIdkaart.Attributes.Add("onClick", "return pagLoad()");
}

}





pagLoad() on see isetehtud Javaskripti funktsioon, mille välja kutsume ja mis selle AJAX-I XMLHttpRequest päringu ära teeb.
function completedHandler() on see Javaskripti funktsioon, mis IdKaart.aspx lehelt info vastu võtab, töötleb ja kontrollib neid ning viib saadud andmed vormile.

Pikemalt on Windowsi Certificate Services Client-ist mille kaudu ID-kaardi majandmine
käib juttu siin.

http://technet.microsoft.com/en-us/library/cc700848.aspx




Blogged with the Flock Browser

neljapäev, 23. juuli 2009

URL RequestFiltering koos ReportViewer Controliga IIS7 peal

IIS7 on veebirakendustele selline tore sisseehitatud võimalus filtreerida GET päringuid URL andmete järgi, ehk rakenduse web.config failis, saab requestFiltering filtering osas ära määrata, kui pikk saab olla maksimaalne
URL ja kui pikk saab olla QUERYSTRING. Aitab näiteks SQL injektsiooni rünnakute vastu.
Kui on ka kasutusel ReportViewer aruannete tegemiseks, tuleb arvestada, et see ReportViewer ise teeb ka palju GET päringuid, mis isenesest võivad olla päris pika QUEYSTRING-iga näiteks
URI: /Reserved.ReportViewerWebControl.axd?Mode=true&ReportID=56afacf3f4c74cd69af397d2b8eefc0b&ControlID=a64ab41370cf4a28ba5967b952cf9038&Culture=1061&UICulture=1061&ReportStack=1&OpType=ReportImage&StreamID=148c7b15-8020-4ce4-9e17-a48043495af8

Otstarbekam on nüüd määrata eraldi web.configis reegel location elemendiga ReportViewerile näiteks niimoodi:


kolmapäev, 22. juuli 2009

Muutujat kasutava SQL päringu kiirendamine OPTION(RECOMPILE) kasutamisega

Üks päring millega päev otsa vaeva nägin. Tehtud täitsa mõistlik SP, mille sees üks päring

DECLARE @apref VARCHAR(1)
SET @apref='C'

SELECT ACCOUNT.ID FROM DBO.ACCOUNT WHERE NOT EXISTS
( SELECT fd.[inv_no] FROM [dbo].[Cust_ Ledger Entry] fd WHERE
fd.[inv_no] = @apref+CAST(ACCOUNT.ID AS VARCHAR(30)) ) AND ACCOUNT.
W_SENT IS NOT NULL

mis töötab aga jube aegalselt

kui päring muuta lihtsalt ilma muutuja kasutamiseta päringuks

SELECT ACCOUNT.ID FROM DBO.ACCOUNT WHERE NOT EXISTS
( SELECT fd.[inv_no] FROM [dbo].[Cust_ Ledger Entry] fd WHERE
fd.[inv_no] = 'C'+CAST(ACCOUNT.ID AS VARCHAR(30)) ) AND ACCOUNT.
W_SENT IS NOT NULL

on asi kiire
Probleem selles, et SQL SERVER-i optimisaator teeb tervele SP-le optimiseerimise ja
SELECT lause koha peal ta ei tea mis on @apref väärtus ja üritab seda pimesi arvata

Üks võimalus on teha dünaamiline SQL aga parem on kasutada OPTION(RECOMPILE) SELECT lause juures

SELECT ACCOUNT.ID FROM DBO.ACCOUNT WHERE NOT EXISTS
( SELECT fd.[inv_no] FROM [dbo].[Cust_ Ledger Entry] fd WHERE
fd.[inv_no] = @apref+CAST(ACCOUNT.ID AS VARCHAR(30)) ) AND ACCOUNT.
W_SENT IS NOT NULL OPTION(RECOMPILE)

sel juhul optimisaator vaatab muutja @apref väärtust päringu tegemise hetkel ja päring läheb kiireks

Asja lahendamise juures olid abiks SQLMONSTERi inimesed
http://www.sqlmonster.com/Uwe/Forum.aspx/sql-server-performance/331/Variable-in-SELECT-expression-causes-query-degradation

reede, 3. juuli 2009

Andmebaasi stuktuuri kaitsmine VIEW DEFINITION õiguse keelamisega PUBLIC rollil

Iga kasutaja, mis MS SQL SERVER-il tehakse ja kellele antakse ligipääs mingile andmebaasile pannaks vaikimisi ka selle andmebaasi PUBLIC rolli. Mille tulemusena saab kasutaja näha, mis protseduurid ja tabelid selles andmebaasis olemas on, ehk näha andmebaasi struktuuri kirjeldust.

Rakenduse toimimiseks ei pruugi aga andmebaasi struktuuri kirjelduse teada olemine üldse vajalik olla. Seda saab piirata, kui keelata andmebaasi PUBLIC rollil VIEW DEFINITION õigus.

DENY VIEW DEFINITION TO public

Lõpeb nüüd asi sellega, et kui kasutaja baasi sisu vaatab ei näe ta sealt midagi. Avab näiteks Management Studioga baasi aga seal ei näita baasi struktuurist mitte kui midagi

Isegi, kui temale on andmebaasisi DB_OWNER õigused antud, siis saab ta näha vaid tabelite sturkuuri aga ei saa tabelite struktuuri muuta.
Saab veateate Tabel TABELINIMI is set to read only, user doesn't have enough rights on this table

Kõrvalnäht, mis kaasneb Visual Studio2008 kasutamisega on see, et kui projektis on datasetid (xsd failid) siis seal sees tabeladapterite muutmisel ei näidata näiteks enam salvestatud protseduuride nimekirja.

Õiguse saab tagasi panna
GRANT VIEW DEFINITION TO public