ProjectDBPlugin - bezpieczny dostęp do baz danych


Autor: Michał Wroński

Wprowadzenie

Wyobraźmy sobie, że grupa osób pracuje nad wspólnym projektem wykorzystując duże moce obliczeniowe. Ludzie ci chcieliby mieć jakąs bazę danych np. z częściowymi wynikami obliczeń i jak najprostszy dostęp do niej. Oczywiście możemy postawić gdzieś DBMS'a, dodać do bazy użytkownikow i hasła ale powoduje to konieczność zapamiętania kolejnego hasła przez każdego z użytkowników. Można oczywiście stosować te same hasła do certyfikatów Unicore'a i do bazy lecz zwiększa to ryzyko przechwycenia hasła przez niepowołane osoby. Najwygodniejszym rozwiązaniem jest wykorzystanie infrastruktury Unicore w celu autoryzacji dostępu do bazy - i to właśnie robi ProjectDBPlugin.

ProjectDBPlugin

ProjectDBPlugin umożliwia na razie dostęp jedynie do PostgreSQL'a. Schemat dzialania jest następujący:

  1. Przygotowanie skryptu w Perlu, komunikującego sie z DBMS i job'a dla NJS
  2. Zlecenie wykonania zadania na danym Vsite
  3. Czekanie na pomyślne zakończenie job'a
  4. Wyświetlenie wyników

PostgreSQL - konfiguracja

Aby w pełni wykorzystać zalety pluginu trzeba ustawić autoryzacje przez ident'a. W pliku pg_hba.conf należy umieścic linie:

# TYPE     DATABASE    IP_ADDRESS     MASK               AUTH_TYPE  AUTH_ARGUMENT
host       mydb        158.75.12.146  255.255.255.255    ident      sameuser

Oznacza to, że użytkownik Jaś łączący się z hosta o numerze IP 158.75.12.146 do bazy mydb będzie miał takie same prawa jak użytkownik Jaś w bazie mydb. Klient nie musi podawać żadnego identyfikatora ani hasła!

ProjectDBPlugin - szczegóły implementacji

Skrypt uruchamiany przez plugin korzysta z dwóch modułów perla: Pg i XML::Dumper. Pierwszy sluży do komunikacji z bazą, drugi zaś umożliwia serializację obiektów perla do XML'a.

	use XML::Dumper;
	use Pg;

	sub script_fail {
	    my $errStr = shift(@_);

	    open(FOUT, "> output");
	    print FOUT $errStr;
	    close FOUT;
	    exit(0);
	}

	sub check_result {
	    my $result = shift(@_);
	    my $conn = shift(@_);

	    if (($result->resultStatus ==PGRES_FATAL_ERROR)    ||
	        ($result->resultStatus == PGRES_NONFATAL_ERROR) ||
	        ($result->resultStatus == PGRES_BAD_RESPONSE))
	    {script_fail($conn->errorMessage);}
	}


	$queryResult = {'nrows' => 0, 'nfields' => 0, 'header' => {}, 'rows' => {}};
	$params = "";

	if ("%PROJDB_HOST")          {$params .= "host=%PROJDB_HOST ";}
	if ("%PROJDB_PORT")          {$params .= "port=%PROJDB_PORT ";}
	if ("%PROJDB_DBNAME")        {$params .= "dbname=%PROJDB_DBNAME ";}
	if ("%PROJDB_USER")          {$params .= "user=%PROJDB_USER ";}
	if ("%PROJDB_PASSWORD")      {$params .= "password=%PROJDB_PASSWORD ";}

	$conn = Pg::connectdb($params);
	if ($conn->status != PGRES_CONNECTION_OK) {script_fail($conn->errorMessage);}

	$result = $conn->exec("%PROJDB_QUERY");
	check_result($result, $conn);

	$$queryResult{'nrows'} = $result->ntuples;
	$$queryResult{'nfields'} = $result->nfields;

	for $i (0..$result->nfields-1){
	    $$queryResult{'header'}{"col".$i} = $result->fname($i);
	}

	$i = 0;
	while(($i < %PROJDB_MAXROWS) && (@row = $result->fetchrow)){
	    check_result($result, $conn);
	    $$queryResult{'rows'}{"row".$i++} = [@row];
	}

	$dump = new XML::Dumper;
	$xml = $dump->pl2xml($queryResult);

	open(FOUT, "> output");
	print FOUT $xml;
	close FOUT;

Jak widać wynik zapytania jest konwertowany do XML'a i zapisywany do pliku, który następnie jest eksportowany do klienta Unicore'a. ProjectDB parsuje go przy pomocy SAX'a i wyświetla wynik w postaci tabelki.

Problemy/Wątpliwości

  1. Autoryzacja na bazie ident'a jest tak bezpieczna jak bezpieczny jest host, na którym działa ident - w naszym przypadku nie stanowi to większego problemu gdyż Vsite jest z zalożenia bezpieczny
  2. Cała tabela jest ładowana do pamięci przed eksportem do XML'a - to także nie stanowi większego problemu gdyż całość i tak jest później przesyłana do klienta, który musi mieć wystarczająca ilość wolnej pamięci. Na wszelki wypadek w ustawieniach projektu można ustawić maksymalną liczbę wierszy, którą chcemy pobierać z bazy.

Pg      XML::Dumper