Maja Górecka-Wolniewicz
UCI UMK Toruń
Maja.Wolniewicz@uni.torun.pl

Temat zadania:

Zastosowanie systemu LDAP do wsparcia usług portalowych oraz systemów pojedynczego logowania

(opracowanie przygotowane w ramach realizacji zadań projektu KBN)

Data opracowania: 11.2003

Spis treści

  1. Wprowadzenie
  2. Funkcjonalność systemów pojedynczego logowania
  3. Uwierzytelnianie poprzez system LDAP w oprogramowaniu uPortal System pojedynczego logowania
    1. Zasada działania CAS-a
    2. Integracja CAS-a z uPortalem
    3. Konfiguracja CAS-a do współpracy z LDAP-em
  4. Przykłady łączenia aplikacji WWW z systemem pojedynczego logowania uPortala
    1. WebMail
    2. Spis pracowników UMK
  5. Ważne linki

1. Wprowadzenie

Usługi portalowe pomału stają się niezbędnym stylem dostępu do zasobów WWW. Pozwalają na dostosowanie domowej strony przeglądarki użytkownika w taki sposób, by było wygodnie dotrzeć do najczęściej używanych zasobów oraz usług sieciowych. Dają spójne środowisko graficzne, umożliwiają łatwe dodanie nowych komponentów. Technologia portalowa pozwala stworzyć środowiskowe zasoby WWW dające się bez problemu dostosować do potrzeb konkretnej grupy użytkowników oraz dostarcza narzędzi wspomagających wymianę informacji poprzez WWW (grupy dyskusyjne, chaty, przeglądy, aktualności).

Zespół Uczelnianego Centrum Informatycznego UMK wybrał oprogramowanie uPortal jako implementację usług portalowych. To bezpłatne oprogramowanie jest rozwijane przez instytucje związane ze szkolnictwem wyższym. Zostało oparte na otwartych standardach, korzysta z Javy, XML-a, JSP. uPortal ma możliwość współpracy z bazą LDAP w celu uwierzytelnienia użytkowników, co w przypadku UMK jest ważne, gdyż ostatnio LDAP stał się tu podstawową bazą użytkowników.

Oprogramowanie portalowe organizuje dostęp do zasobów informacyjnych oraz do usług sieciowych. Coraz częściej zdarza się, że określone zasoby czy usługi wymagają autoryzowanego dostępu, gdyż nie każdy ma prawo z nich korzystać. Użytkownik portala zazwyczaj nie jest anonimowy - już w celu dopasowania wyglądu stron do własnych potrzeb musi dokonać uwierzytelnienia. To jednokrotne uwierzytelnienie, wykonane w chwili pierwszego kontaktu z portalem powinno dawać możliwość dostępu do wszystkich usług i zasobów, z których dany użytkownik ma prawo korzystać. Taki uniwersalny system jest nazywany system pojedynczego logowania (single sign-on).

2. Funkcjonalność systemów pojedynczego logowania

Systemy pojedynczego logowania realizują dwa istotne zadania:

  1. dokonują uwierzytelnienia użytkownika na podstawie otrzymanych danych uwierzytelniających, przy czym zazwyczaj dają możliwość zastosowania różnego rodzaju technik uwierzytelniania;
  2. za pomocą ustalonego wewnętrznie mechanizmu potrafią ustanowić sesję dotyczącą konkretnego użytkownika, w trakcie której może on bez ponownego podawania danych uwierzytelniania korzystać z zarejestrowanych w tym systemie usług sieciowych.
Drugi aspekt działania systemu pojedynczego logowania jest kluczowy, nie tylko dlatego, że czyni z niego system pojedynczego logowania. Niezbędna jest taka realizacja tej funkcjonalności, by zapewnić bezpieczeństwo całego systemu i uniemiemożliwić wszelki nielegalny dostęp, a również przechwycenie hasła które dzięki temu systemowi stało się kluczem dostępu do wielu aplikacji. Zazwyczaj systemy pojedynczego logowania współpracują nie tylko z aplikacjami WWW, lecz również usługami bazowymi, z których z kolei korzystają aplikacje WWW, jak np. imapd czy popd.

3. Uwierzytelnianie poprzez system LDAP w oprogramowaniu uPortal

uPortal daje możliwość korzystania z bazy LDAP do uwierzytelniania użytkowników portala. W tym celu w pliku properties/ldap.properties dystrybucji uPortala (przy tego typu dostosowaniach oprogramowania należy używać dystrybucji uPortal-only, a nie Quick start) ustawiamy odpowiednio wartości:
ldap.host=pełna kwalifikowana nazwa serwera LDAP
ldap.port=port serwera LDAP
ldap.protocol=SSL # jeśli chronimy hasła poprzez stosowanie SSL-a
ldap.baseDN=nazwa wyróżniona kontekstu startowego
ldap.uidAttribute=atrybut używany do wyszukiwania użytkownika, np.  uid

oraz, jeśli jest to potrzebne do uzyskania dostępu do bazy,
ldap.managerDN=nazwa wyróżniona administratora
ldap.managerPW=hasło administratora
Następnie w pliku properties/PersonDirs.xml, definiującym sposób dostępu do danych o użytkowniku, wybieramy metodę "LDAP Properties" w bloku <PersonDirInfo> i ustawiamy:
<url>ldap://nazwa_serwera_ldap:port_serwera_LDAP/kontekst_bazowy</url>
<uidquery>uid={0})</uidquery>
<usercontext>ou=Users<usercontext>
Znacznik uidquery pozwala zdefiniować atrybut wyszukania, natomiast usercontext określa kontekst przeszukania (w zakresie podanego bazowego URL-a). Znaczniki <logonid> oraz <logonpassword> są używane do wskazania nazwy i hasła w przypadku, gdy dostęp do bazy LDAP nie może być anonimowy. Następnie w bloku <attributes> definiujemy nazwy atrybutów w bazie LDAP.

Kolejnym krokiem jest określenie sposobu uwierzytelniania. Jeśli chcemy korzystać z bazy LDAP, to konieczna jest zmiana w pliku properties/security.properties, musi w nim wystąpić wiersz:

root=org.jasig.portal.security.provider.SimpleLdapSecurityContextFactory 
lub
root=org.jasig.portal.security.provider.CacheLdapSecurityContextFactory 
W drugim przypadku pobrane z LDAP-a dane uwierzytelniania są cache'owane przez aplikację i mogą być używane przy kolejnych próbach uwierzytelnienia. Jest to metoda symulowania systemu pojedynczego logowania, ale należy podkreślić, że nie jest to zalecane podejście z powodów bezpieczeństwa, gdyż w takim podejściu hasło jest przechowywane otwartym tekstem w pamięci aplikacji. Jeśli zalogowanie w uPortalu ma oznaczać dostęp do wszystkich innych usług sieciowych oferowanych w ramach portala (np. WebMail, dostęp do zasobów pracowniczej bazy danych czy do elektronicznych czasopism prenumerowanych przez macirzystą instytucję), to niezbędne jest wdrożenie profesjonalnego systemu pojedynczego logowania.

4. System pojedynczego logowania

Zespół UMK zdecydował się na wykorzystanie jako systemu pojedynczego logowania oprogramowania rozwijanego na uniwersytecie w Yale, o nazwie Central Authentication Service, CAS. CAS działa bardzo dobrze, gdy mamy kontrolę nad sposobem uwierzytelniania realizowanym przez nasze aplikacje oraz gdy jesteśmy w stanie dostosować obce aplikacje przez dodanie interfejsów dla funkcji uwierzytelniania. Gwarantuje też duży poziom bezpieczeństwa, gdyż hasła są przekazywane wyłącznie między przeglądarką a serwerem uwierzytelniania (serwerem CAS), a transfer hasła odbywa się poprzez szyfrowany tunel.

a. Zasada działania CAS-a

Z CAS-a można korzystać na wiele sposobów. Jedną z metod jest wykorzystanie modułu mod_cas w serwerze HTTP Apache (wersji 1.x lub 2.x). Moduł ten dostarcza usługi uwierzytelniania oraz autoryzacji dostępu. Są również dostępne bublioteki klas umożliwiające współpracę z CAS-em z aplikacji w Javie, czy z serwletów Javy. Z kolei moduł pam_cas umożliwia integrację technologii PAM z CAS-em. Sam CAS to aplikacja WWW, działająca poprzez SSL. Sesja CAS jest typowo inicjowana za pomocą URL-a:
https://nazwa_serwera_cas/cas/login?service=http://nazwa_serwera_uportal/uPortal/Authentication
który przy pierwszym odwołaniu kieruje użytkownika do formularza uwierzytelniania, np. w polach nazwa użytkownika i hasło podajemy swoje dane, które są przekazywane do serwera CAS.

Podobnie jak uPortal, CAS może zostać skonfigurowany tak, by korzystał z dowolnych, zaimplementowanych w systemie metod uwierzytelniania, na przykład z Kerberosa czy LDAP-a.

W najprostszym przypadku CAS sprawdza nazwę użytkownika i hasło, jeśli weryfikacja powiedzie się, to generuje bilet (ticket), który zostaje przesłany do URL-a wskazanego w parametrze service, czyli do docelowej aplikacji, ubiegającej się o uwierzytelnienie (w tym przypadku uPortal). Aplikacja musi przekazać bilet z powrotem do CAS-a, razem z parametrem service wskazującym, kto odebrał bilet. Bilet po jednokrotnym użyciu traci ważność i nie może być ponownie użyty. Gdy użytkownik zostanie uwierzytelniony CAS ustanawia cookie. Jeśli inna usługa przekieruje użytkownika do strony cas/login, to serwer CAS jest w stanie rozpoznać, że dany użytkownik już został uwierzytelniony i automatycznie wygenerować mu bilet i przekierować do docelowej aplikacji bez konieczności wypełniania formularza uwierzytelniania, czyli uzyskujemy efekt pojedynczego logowania.

Najnowsze wersje CAS-a (serii 2.0) mogą nie tylko uwierzytelnić użytkownika. CAS 2.0 może również przyznać aplikacji prawa do uwierzytelniania pośredniego (proxy authentication). Usługa proxy pozwala na "wcielenie się" w użytkownika, odegranie jego roli wobec innej usługi sieciowej. W tym scenariuszu CAS przekazuje aplikacji występującej jako proxy (np. uPortal), bilet typu PGT, proxy granting ticket, dotyczący konkretnego użytkownika. Aplikacja, gdy musi uwierzytelnić tego użytkownika w kolejnej usłudze, przesyła bilet PGT do CAS-a, a CAS zwraca bilet dla danego użytkownika. Wówczas aplikacja wywołuje URL związany z logowaniem, przekazując bilet, a proxy dostaje z serwera CAS nazwę użytkownika. Może istnieć łańcuch aplikacji mających prawo występowania jako proxy, dlatego CAS zwraca oprócz nazwy użytkownika listę aplikacji typu proxy granting. Dzięki temu docelowa aplikacja może decydować, czy zaakceptować informację dotyczącą uwierzytelnienia.

b. Integracja CAS-a z uPortalem

System CAS może zostać zintegrowany z uPortalem - służy do tego klasa org.jasig.portal.security.provider.YaleCasContextFactory. Razem z klienckimi bibliotekami CAS klasa ta umożliwia uPortalowi sprawdzenie poprawności biletu CAS i uzyskanie nazwy uwierzytelnionego użytkownika oraz biletu PGT, używanego następnie do uwierzytelniania w kolejnych aplikacjach.

W celu integracji należy wykonać następujące czynności:

  1. Zainstalować cas-server.
    Serwer CAS to aplikacja WWW, zgodna z technologią Servlet 2.3. Włączenie tej aplikacji polega na utworzeniu pliku .war (web-application archive) i dodanie go do aplikacji Tomcata. Polecenie
    	ant dist
    
    dokona kompilacji plików źródłowych Javy (katalog src), powstaną pliki .class w katalogu build. Powstanie również plik .jar, zawierający wszystkie skompilowane klasy, który zostanie zainstalowany w podkatalogu drzewa web (dokładnie w katalogu web/WEB-INF/lib) oraz plik .war, stanowiący zawartość katalogu web (w katalogu lib). Plik lib/cas.war musi zostać umieszczony w katalogu aplikacji Tomcata (np. /usr/local/tomcat/webapps).

    Domyślnie dystrybucja serwera CAS generuje pusty kod uwierzytelniania, co oznacza, że serwer CAS uwierzytelni każdego użytkownika podającego taki sam ciąg znaków jako nazwę użytkownika i hasło. Aby zastosować własny schemat uwierzytelniania, np. poprzez serwis LDAP, należy odpowiednio zmodyfikować klasy związane z uwierzytelnianiem (edu.yale.its.tp.cas.auth) - będzie o tym mowa w dalszej części opracowania.

  2. Zainstalować pakiet cas-client w zakresie bibliotek Java.

    Biblioteka java/lib/casclient.jar musi zostać udostępniona aplikacji uPortal. Należy przekopiować ją do katalogu lib dystrybucji uPortala.

  3. Zainstalować pakiet cas-uportal.
    Dystrybucja zawiera w katalogu properties pliki portal.properties.fragment i security.properties. Pierwszy z nich należy dołączyć do dystrybucji uPortala, do pliku properties/portal.properties (oczywiście niezbędna jest modyfikacja zawartości w celu wskazania właściwych nazw serwerów i ścieżek). Drugi plik wskazuje, jak należy dostosować konfigurację uPortala w zakresie parametrów bezpieczeństwa definiowanych w pliku properties/security.properties Konieczna jest również modyfikacja pliku webpages/WEB-INF/web.xml dystrybucji uPortal zgodnie ze wskazówkami zawartymi w pliku webpages/WEB-INF/web.xml dystrybucji cas-uPortal. Kolejny krok to dodanie klas YaleCasContext.java oraz YaleCasContextFactory.java do katalogu source/org/jasig/portal/security/provider dystrybucji uPortala.
Po tych czynnościach powinien działać już adres:
https://nazwa_serwera_cas/cas/login?service=http://nazwa_serwera_uportal/uPortal/Authentication
Należy pamiętać, że serwer CAS musi pracować w oparciu o protokół SSL (bezpieczny port). Wymaga to odpowiedniego skonfigurowania Tomcata, wg poniższej procedury (zakładamy, że cas.crt jest certyfikatem serwera CAS, ca.crt certyfikatem centrum, które wystawiło certyfikat serwerowi CAS): W magazynie kluczy CA maszyny wirtualnej Javy trzeba jeszcze umieścić certyfikat CA (ca.crt).
Dokonujemy transformacji ca.crt do postaci DER
openssl x509 -in ca.crt -out ca.der -outform DER
i integrujemy plik ca.der z podsystemem JVM
keytool -import -alias UMK-CA -file ca.der -keystore	$JAVA_HOME/jre/lib/security/cacerts -storepass changeit
Sprawdzamy zawartość magazynu cecerts
keytool -list -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit

c. Konfiguracja CAS-a do współpracy z LDAP-em

Domyślnie za uwierzytelnienie w systemie CAS jest odpowiedzialna klasa edu/yale/its/tp/cas/auth/provider/SampleHandler.class, która pozytywie uwierzytelni każdego użytkownika podającego hasło takie samo jak nazwa logowania. Aby zmienić sposób uwierzytelniania należy dodać nową klasę realizującą ustaloną technikę uwierzytelniania. Jednym z rozwiązań jest umieszczenie w katalogu src/edu/yale/its/tp/cas/auth/provider dystrybucji cas-server klasy LDAPHandler.java. Poniżej jest przedstawiona jej przykładowa postać:
package edu.yale.its.tp.cas.auth.provider;

import edu.yale.its.tp.cas.auth.*;
import netscape.ldap.*;
import java.util.*;

/** Interface for password-based authentication handlers. */
public class LDAPHandler implements PasswordHandler {
 public boolean authenticate(javax.servlet.ServletRequest request,
                       String username,
                       String password) {
				String LDAPhost = "ldap.uci.uni.torun.pl";
        String FILTER = "uid="+username;
        String SEARCHBASE = "ou=Users,dc=uni,dc=torun,dc=pl";

        LDAPConnection ld = new LDAPConnection();
        String EntryDN = null;
        String ManagerEntryDN = "cn=Manager,dc=uni,dc=torun,dc=pl";
        try {
                ld.connect( LDAPhost, LDAPv2.DEFAULT_PORT);
                ld.authenticate ( 3, ManagerEntryDN, "secret" );
                LDAPSearchResults res = ld.search( SEARCHBASE,
                        LDAPConnection.SCOPE_SUB,
                        FILTER, null, false );
                while ( res.hasMoreElements() ) {
                        LDAPEntry findEntry = null;
                        try {
                                findEntry = res.next();
                                EntryDN = findEntry.getDN();
                        } catch ( LDAPException e ) {
                                return(false);
                        }
                }
                try {
                        ld.authenticate(3, EntryDN, password);
                } catch( LDAPException e ) {
                        return(false);  
                }
        } catch( LDAPException e ) {
                return(false);
        }
				try {
                ld.disconnect();
        } catch( LDAPException e ) {
                return(false);
        }
        return(true);
 }
}
W pliku web/WEB-INF/web.xml dystrybucji modyfikujemy blok <context-param> zawierający wiersz:
<param-name>edu.yale.its.tp.cas.authHandler<param-name>
zmieniamy wiersz <param-value> na:
<param-value>edu.yale.its.tp.cas.auth.provider.LDAPHandler<param-value>
Po rekompilacji (ant dist) przekopiowujemy nowy plik lib/cas.war do katalogu $TOMCAT_HOME/webapps i usuwamy zawartość katalogu $TOMCAT_HOME/webapps/cas. Następnie restartujemy Tomcata.

Po tych modyfikacjach procedura uwierzytelniania jest realizowana w oparciu o bazę LDAP (w tym przypadku w gałęzi ou=Users,dc=uni,dc=torun,dc=pl wyszukujemy podanej nazwy użytkownika poprzez filtr: uid=nazwa_użytkownika; po skutecznym znalezieniu wpisu, realizowana jest próba dowiązania do bazy jako wyszukany użytkownik przy użyciu podanego hasła; Pozytywne dowiązanie oznacza sukces procesu uwierzytelnienia).

Ponieważ serwer CAS działa jako system pojedynczego logowania, po pierwszym uwierzytelnieniu, kolejne aplikacje mogą korzystać z funkcjonalności CAS-a oraz uPortala, który w tej sytuacji może występować jako aplikacja proxy-granting.

5. Przykłady łączenia aplikacji WWW z systemem pojedynczego logowania uPortala

Jako przykład zastosowania mechanizmu pojedynczego logowania w uPortalu prezentujemy wdrożenie dwóch kanałów:
  1. dostęp do WebMaila poprzez aplikację IMP;
  2. dostęp do spisu pracowników Uniwersytetu Mikołaja Kopernika w Toruniu (wg następującego klucza: właściciele kont pracowniczych uzyskują pełny dostęp do danych, pozostali użytkownicy mają dostęp do informacji zawężonej do pracowników akademickich i kierowników jednostek).

a. WebMail

W celu powiązania dostępu do interfejsu IMP z systemem pojedynczego logowania został przygotowany specjalny kanał stanowiący łącznik pomiędzy uPortalem a aplikacją IMP. Jako wzorzec posłużył kanał opisany na stronie http://www.eng.uwaterloo.ca/~bruce/uportal/horde.html. Opracowanie kanału objęło: Konieczne są również niewielkie modyfikacje po stronie aplikacji Horde IMP. Obejmują one: Ostatni krok to dostosowanie sposobu uwierzytelniania realizowanego przez serwer imapd. Przede wszystkim serwer ten musi korzystać z PAM-a. W konfiguracji /etc/pam.d/imap (opis dotyczy systemu Redhat) wpisujemy:
auth sufficient /lib/security/pam_cas.so debug -simap://imap.uci.uni.torun.pl -phttps://portal.uci.uni.torun.pl:8443/uPortal2CasProxyServlet
auth required /lib/security/pam_pwdb.so shadow nullok
account required /lib/security/pam_pwdb.so shadow nullok
Bilioteka /lib/security/pam_cas.so pochodzi z pakietu cas-client (jest wynikiem kompilacji w katalogu pam_cas dystrybucji cas-client).

Tak przygotowany kanał razem z modyfikacją konfiguracji IMAP i kilku fragmentów aplikacji IMP dają możliwość dostępu do poczty ze środowiska uPortal bez konieczności ponownego uwierzytelniania.

b. Spis pracowników UMK

Interfejs o adresie http://ldap.uci.uni.torun.pl udostępnia spis osobowy pracowników UMK. Spis ten, zgodnie z zarządzeniem J.M. Rektora (zarządzenie) nie może być dostępny bez ograniczeń. Przyjęto następujące rozwiązanie: użytkownik korzystający zawierających spis pracowników UMK bez wcześniejszego zalogowania ma dostęp do części danych (jednostki, podjednostki, pracownicy akademiccy, kadra kierownicza oraz ci pracownicy, których kierownicy zlecili upublicznienie danych). Pracownicy UMK posiadający konta w sieci komputerowej UMK mogą po zalogowaniu uzyskać dostęp do pełnych danych. Adres serwisu oferującego spis może zostać dołączony jako oddzielny kanał środowiska uPortal. W celu realizacji funkcjonalności pojedynczego logowania moduł logowania został zintegrowany z usługą CAS. Ponieważ aplikacja dostępowa do bazy pracowników jest opracowana w języku PHP, zastosowano pakiet phpCAS. Strona startowa usługi, np. start.php ma następującą postać:
<?php
include ('./config.php');
include ('./lib/general.inc');
include_once('CAS/CAS.php');
include_once('CAS/client.php');

session_start();

phpCAS::client(CAS_VERSION_2_0,'cas.uci.uni.torun.pl',8443,'cas');
if ( phpCAS::authenticate() ) {
# zmienna której ustawienie decyduje o przyznaniu pełnego dostępu
        $_SESSION['zmienna']=1; 
        $_SESSION['cachedData']=array();
} 


$newbase = 0;

if (isset($_GET['base']) && $_GET['base']) $newbase = urlencode(urldecode($_GET[
'base']));
if (isset($_GET['entry']) && $_GET['entry']) $entry = urlencode(urldecode($_GET[
'entry']));
 
?>

<html>
<head>
<title>LDAP-USER</title>
<meta http-equiv="content-type" content="text/html;charset=ISO-8859-2">

</head>

<frameset  cols="35%,*"  framespacing="0">

  <frame  marginheight="4" marginwidth="4" src="tree.php<?= $newbase ? "?newbase
=$newbase" : "" ?>" name="left">
  <frame  marginheight="4" marginwidth="4" src="entry.php<?= $entry ? "?actionID
=23&dn=$entry" : "" ?>" name="right">

</frameset>

</html>
?>
Wywołanie funkcji phpCAS::authenticate(), mające miejsce po zainicjowaniu powiązania z serwerem CAS decyduje o wyniku uwierzytelnienia. Jeśli użytkownik jest znany serwerowi CAS, wynik wywołania jest pozytywny i nie jest potrzebne odesłanie do formularza logowania.

Ważne linki