czechidm-progdoc - Programátorská dokumentace

Transkript

czechidm-progdoc - Programátorská dokumentace
CzechIdM 1.1
czechidm-progdoc
Programátorská dokumentace
Jan Gregor
Jaromír Mlejnek
Jana Moudrá
Vojtěch Matocha
czechidm-progdoc
CzechIdM 1.1 czechidm-progdoc
Programátorská dokumentace
Vydání 0
Autor
Autor
Autor
Autor
Jan Gregor
Jaromír Mlejnek
Jana Moudrá
Vojtěch Matocha
© 2012 BCV solutions s.r.o..
Red Hat, Red Hat Enterprise Linux, Shadowman logo, JBoss, MetaMatrix, Fedora, Infinity Logo a
RHCE jsou ochranné známky Red Hat, Inc. registrované v USA a dalších zemích.
Linux® je ochranná známka Linuse Trovaldse v USA a dalších zemích.
Java® je ochranná známka Oracle.
7. května 1168/70
Praha 4 - Chodov, 149 00Czech Republic
Phone: +420 602 275 444
Tento text vznikl jako programátorská dokumentace Identity Manageru CzechIdM. Obsahuje stručný
přehled důležitých součástí CzechIdM a bližší vysvětlení některých komplikovanějších oblastí.
Dokumentace by měla sloužit všem vývojářům CzechIdM, kromě obecného modelu obsahuje návody
na vytváření workflow, pravidel, e-mailových šablon, testů, konektorů a nových stránek a formulářů.
Text napomůže čtenáři proniknout do existujícího kódu CzechIdM a ozřejmí mu vztahy mezi datovou,
aplikační a prezentační vrstvou a klíčové metody, jimiž mezi sebou tyto vrstvy komunikují. Dokument
není uživatelským manuálem CzechIdM, je určen člověku, který chce aktivně měnit zdrojový kód
CzechIdM nebo pochopit souvislosti v kódu již existujícím.
Preface
ix
1. Hlášení chyb .................................................................................................................. ix
1. Struktura systému
1.1. Třívrstvá architektura ....................................................................................................
1.2. Moduly a jejich topologie ..............................................................................................
1.3. Webové rozhraní ..........................................................................................................
1.3.1. Implementační detaily ........................................................................................
1.3.2. Repository .........................................................................................................
1.3.3. Použité technologie ...........................................................................................
1
1
2
5
5
6
7
2. Aplikační vrstva
9
2.1. Přihlašování ................................................................................................................. 9
2.2. Workflow, pravidla a e-mailové šablony ....................................................................... 10
2.2.1. Předávání proměnných mezi procesy ................................................................ 10
2.3. Bussiness konstanty ................................................................................................... 11
2.4. Pravidlo getExtendedAttributesNames ......................................................................... 11
2.5. Modul Utils ................................................................................................................. 11
3. Datová vrstva
3.1. Entity .........................................................................................................................
3.1.1. Hierarchie entit ................................................................................................
3.1.2. View ...............................................................................................................
3.2. Obecné třídy uchovávající data ...................................................................................
3.2.1. DTOModifiable <T> ....................................................................................
3.2.2. DTO .................................................................................................................
3.2.3. DTOModification .........................................................................................
3.2.4. DTOGroup .......................................................................................................
3.2.5. DTOList<E> ...................................................................................................
3.2.6. DTOLinkedList<E> .......................................................................................
3.2.7. View ...............................................................................................................
3.2.8. GenericView .................................................................................................
3.2.9. UserView .......................................................................................................
3.2.10. Extended atributy ...........................................................................................
3.2.10.1. Návrh .................................................................................................
3.2.10.2. Třída ExtendedAttribute ................................................................
3.3. View handlery ............................................................................................................
3.3.1. Metoda ViewHandler.createEmptyView ..............................................................
3.3.2. Metoda ViewHandler.createView .......................................................................
3.3.3. Metoda ViewHandler.processViewChanges .......................................................
3.4. Třída Data .................................................................................................................
3.4.1. Získání pohledu na existující entitu - metoda Data.checkoutView ...................
3.4.1.1. Získání příslušného managementu .........................................................
3.4.1.2. Metoda createView v rozhraní ViewHandler .....................................
3.4.1.3. Vytvoření pohledu na identitu .................................................................
3.4.2. Získání pohledu pro čtení na existující entitu - metoda
Data.getReadOnlyView ........................................................................................
3.4.3. Získání ořezaného pohledu na existující entitu - metoda
Data.checkoutTrimmedView .................................................................................
3.4.4. Zpracování změn ve View - metoda Data.checkinView .................................
3.4.4.1. Získání příslušného managementu .........................................................
3.4.4.2. Metoda saveView ................................................................................
3.4.4.3. Provisioning ..........................................................................................
13
13
13
13
14
14
14
14
14
15
15
15
15
15
16
16
17
17
17
17
18
18
18
18
18
18
19
19
19
19
20
20
iii
czechidm-progdoc
3.4.4.4. Uvolnění zámku ....................................................................................
3.4.5. Specifika metody Data.checkinView pro parametr typu UserView .................
3.4.5.1. Workflow "user.before.checkin" v metodě beforeSaveView ...................
3.4.5.2. Metoda processViewChanges na třídě UserViewHandler ..................
3.4.5.3. UserProvisioning ...................................................................................
3.4.6. Další užitečné metody na třídě Data ................................................................
3.4.6.1. Data.addRoleWithoutApprovement .................................................
3.4.6.2. Data.delete ......................................................................................
3.4.6.3. Data.getEntityId ............................................................................
3.4.6.4. Data.getLoggedUserName ................................................................
3.4.6.5. Data.getSchemaId ............................................................................
3.4.6.6. Data.listIds ....................................................................................
3.4.6.7. Data.setUserAccountsEnabled ......................................................
3.4.6.8. Data.listResourceSchemas ............................................................
3.4.6.9. Data.deleteAccount ........................................................................
3.5. Criteria .................................................................................................................
20
20
20
21
22
22
22
22
22
22
22
23
23
23
23
23
4. Prezentační vrstva
4.1. Použité technologie ....................................................................................................
4.2. Členění uživatelského rozhraní ...................................................................................
4.3. Třída GenericManagedBean .....................................................................................
4.3.1. Metoda getPageParameters .........................................................................
4.3.2. Metoda processSubmit .................................................................................
4.3.3. Metoda processAction .................................................................................
4.3.4. Metoda processActionWithNewWorkflow ...................................................
4.4. JSF šablony ...............................................................................................................
4.5. Psaní formulářů pomocí JSF a workflow ......................................................................
4.5.1. Spuštění nového workflow ................................................................................
4.5.2. Propojení JSF šablon a workflow ......................................................................
4.5.3. Zobrazení dat workflow v JSF stránce ..............................................................
4.5.4. Ovlivnění již běžícího workflow .........................................................................
4.5.5. Internacionalizace ............................................................................................
25
25
25
25
25
25
25
26
26
26
26
27
28
29
29
5. Workflow
5.1. Jak vytvořit workflow ..................................................................................................
5.1.1. Úvod ...............................................................................................................
5.1.2. Ukázkové workflow ..........................................................................................
5.2. Notifikace pomocí e-mailu ...........................................................................................
5.3. Workflow engine .........................................................................................................
5.3.1. Předdefinované proměnné ...............................................................................
5.4. Metody související s workflow na třídě Application ........................................................
5.5. Výstupní hodnota .......................................................................................................
31
31
31
32
36
36
37
38
38
6. Pravidla
6.1. Pravidla .....................................................................................................................
6.2. Ukázkové pravidlo ......................................................................................................
6.3. Rule engine ...............................................................................................................
6.4. Transformační pravidla ...............................................................................................
6.5. Pravidla pro výpočet nové hodnoty atributu ..................................................................
6.6. Korelační pravidla .......................................................................................................
6.7. Pravidla pro blokování účtů .........................................................................................
6.8. Pravidla before provisioning a after provisioning ...........................................................
39
39
39
40
40
41
41
42
42
iv
7. Logování
7.1. Úvod do logování v CzechIdM ....................................................................................
7.2. Co všechno je logováno? ...........................................................................................
7.3. Auditní informace .......................................................................................................
7.4. Uživatelské požadavky ...............................................................................................
7.5. Identifikátor požadavku ...............................................................................................
7.6. Začátek a konec uživatelského požadavku ..................................................................
7.7. Zápis logu ..................................................................................................................
7.8. Jak logovat z kódu .....................................................................................................
45
45
45
45
45
46
46
47
47
8. Schvalování
8.1. Schvalovací proces ....................................................................................................
8.1.1. Pohled uživatele ..............................................................................................
8.1.2. Pohled administrátora ......................................................................................
8.1.3. Pohled vývojáře ...............................................................................................
8.1.4. Příklad vytvoření schvalovací úlohy ve workflow ................................................
8.2. Delegace schvalovacích procesů .................................................................................
8.2.1. Pohled uživatele ..............................................................................................
8.2.2. Pohled vývojáře ...............................................................................................
49
49
49
49
50
52
52
52
52
9. Plánování úloh
55
9.1. Scheduler a task executer .......................................................................................... 55
10. Koncové systémy
10.1. Definice koncového systému .....................................................................................
10.1.1. Pravidla spouštěná před a po operaci na systému ...........................................
10.1.2. Nastavení způsobu blokování (a odblokování) účtu ..........................................
10.2. Přilinkování uživatelského účtu ..................................................................................
10.3. Vypnutí reálných modifikací systému .........................................................................
10.4. Aktualizace hodnot atributů účtů na koncových systémech ..........................................
10.4.1. Aktualizace z hlediska identity ........................................................................
10.4.2. Aktualizace z hlediska rolí ..............................................................................
10.4.3. Standardní řešení výpočtu hodnot typu "merge" ...............................................
57
57
57
57
57
58
58
59
59
60
11. Identity Connectors
11.1. Definice konektoru ....................................................................................................
11.2. Lokální a vzdálený connector server ..........................................................................
11.3. Funcionalita konektorů ..............................................................................................
11.4. Spouštění externích skriptů na koncových systémech .................................................
11.5. Struktura tříd Universal JDBC konektoru ....................................................................
11.6. Jak použít Universal JDBC Connector .......................................................................
11.6.1. Konfigurace konektoru ....................................................................................
11.6.2. Skript CREATE ..............................................................................................
11.6.3. Skript CREATE ..............................................................................................
11.6.4. Skript UPDATE ..............................................................................................
11.6.5. Skript DELETE ...............................................................................................
11.6.6. Skript LISTALL ...............................................................................................
11.6.7. Skript SCHEMA .............................................................................................
11.6.8. Skript GET .....................................................................................................
11.6.9. Skript SYNC ..................................................................................................
11.6.10. Skript GET_LAST_SYNC_TOKEN .................................................................
11.7. Database Table konektor ...........................................................................................
11.8. SSH konektor ...........................................................................................................
63
63
63
63
64
64
65
65
66
66
69
72
74
76
77
79
80
80
82
v
czechidm-progdoc
11.8.1.
11.8.2.
11.8.3.
11.8.4.
11.8.5.
11.8.6.
11.8.7.
11.8.8.
11.8.9.
Konfigurace konektoru ....................................................................................
Skript Create .................................................................................................
Skript Update .................................................................................................
Skript Delete ..................................................................................................
Skript DisableUser .........................................................................................
Skript EnableUser ..........................................................................................
Skript ListObjects ...........................................................................................
Skript AttributesSchema .................................................................................
Příklad univerzálního skriptu ...........................................................................
82
83
84
84
84
84
85
85
85
12. Typické procesy správy životního cyklu identit
93
12.1. Závislosti mezi procesy ............................................................................................. 93
12.2. Proces "Příchod zaměstnance" .................................................................................. 94
12.2.1. Souhrn .......................................................................................................... 94
12.2.2. Popis procesu "Příchod zaměstnance" ............................................................ 94
12.2.3. Diagram ........................................................................................................ 95
12.3. Proces "Přidat oprávnění uživateli" ............................................................................ 96
12.3.1. Souhrn .......................................................................................................... 96
12.3.2. Popis procesu "Přidat oprávnění uživateli" ....................................................... 96
12.3.3. Diagram ........................................................................................................ 97
12.4. Proces "Odebrat oprávnění uživateli" ......................................................................... 97
12.4.1. Souhrn .......................................................................................................... 97
12.4.2. Popis procesu "Odebrat oprávnění uživateli" .................................................... 98
12.4.3. Diagram ........................................................................................................ 99
12.5. Proces "Povolení systémů" ....................................................................................... 99
12.5.1. Souhrn .......................................................................................................... 99
12.5.2. Popis procesu "Povolení systémů" ................................................................ 100
12.5.3. Diagram ...................................................................................................... 100
12.6. Proces "Zakázání systémů" ..................................................................................... 101
12.6.1. Souhrn ........................................................................................................ 101
12.6.2. Popis procesu "Zakázání systémů" ............................................................... 101
12.6.3. Diagram ...................................................................................................... 102
12.7. Proces "Změna popisných dat uživatele" .................................................................. 102
12.7.1. Souhrn ........................................................................................................ 102
12.7.2. Popis procesu "Změna popisných dat uživatele" ............................................. 103
12.7.3. Diagram ...................................................................................................... 104
12.8. Proces "Změna uživatelských atributů" ..................................................................... 104
12.8.1. Souhrn ........................................................................................................ 104
12.8.2. Popis procesu "Změna uživatelských atributů" ............................................... 105
12.8.3. Diagram ...................................................................................................... 105
12.9. Proces "Změna pracovní pozice" ............................................................................. 105
12.9.1. Souhrn ........................................................................................................ 105
12.9.2. Popis procesu "Změna pracovní pozice" ........................................................ 106
12.9.3. Diagram ...................................................................................................... 107
12.10. Proces "Vyjmutí z evidenčního počtu" .................................................................... 107
12.10.1. Souhrn ...................................................................................................... 107
12.10.2. Popis procesu "Vyjmutí z evidenčního počtu" ............................................... 107
12.10.3. Diagram ..................................................................................................... 108
12.11. Proces "Přesun pracovní pozice" ........................................................................... 108
12.11.1. Souhrn ....................................................................................................... 108
12.11.2. Popis procesu "Přesun pracovní pozice" ...................................................... 109
12.11.3. Diagram ..................................................................................................... 109
vi
12.12. Proces "Provedení časované události" ...................................................................
12.12.1. Souhrn ......................................................................................................
12.12.2. Popis procesu "Provedení časované události" ..............................................
12.12.3. Diagram .....................................................................................................
12.13. Proces "Ukončení PPV" ........................................................................................
12.13.1. Souhrn ......................................................................................................
12.13.2. Popis procesu "Ukončení PPV" ...................................................................
12.13.3. Diagram .....................................................................................................
12.14. Proces "Smazání uživatele" ...................................................................................
12.14.1. Souhrn ......................................................................................................
12.14.2. Popis procesu "Smazání uživatele" .............................................................
12.14.3. Diagram .....................................................................................................
12.15. Proces "Vyjmutí z karantény" .................................................................................
12.15.1. Souhrn ......................................................................................................
12.15.2. Popis procesu "Vyjmutí z karantény" ...........................................................
12.15.3. Diagram .....................................................................................................
12.16. Obecné řešení karantény ......................................................................................
110
110
110
111
111
111
111
112
112
112
112
113
113
113
114
114
114
13. Konfigurace
115
13.1. Přehled konfiguračních parametrů ........................................................................... 115
14. Webová služba
14.1. Návrhový diagram tříd .............................................................................................
14.1.1. Metoda login ................................................................................................
14.1.2. Metoda logout ..............................................................................................
14.1.3. Metoda launchWorkflowAsynchronously ........................................................
14.1.4. Metoda launchWorkflowSynchronously ..........................................................
14.1.5. Metoda launchWorkflowAsynchronouslyStringVars .........................................
14.1.6. Metoda launchWorkflowSynchronouslyStringVars ...........................................
14.2. Asynchronní volání metod JAX-WS .........................................................................
14.3. Zamezení logování WARN [StatelessBeanContext] EJBTHREE-1337 .........................
117
117
117
117
118
118
118
118
119
119
15. Password filter
15.1. Instalace password filteru na Windows .....................................................................
15.2. Konfigurace password filteru ....................................................................................
15.3. Vytvoření password filteru .......................................................................................
15.4. Komunikace password filteru s CzechIdM přes webovou službu .................................
15.5. Synchronizace hesel na straně CzechIdM ................................................................
15.6. Zabezpečení přes SSL ............................................................................................
15.7. Rizika a bezpečnostní opatření ................................................................................
15.8. Užitečné informace pro vývoj a testování .................................................................
121
121
121
122
122
123
123
124
124
16. Testování
16.1. Testování kódu .......................................................................................................
16.2. Jak napsat jednoduchý test .....................................................................................
16.3. Práce s výjimkami ..................................................................................................
16.4. Když záleží na pořadí .............................................................................................
16.5. Psaní testů EJB session bean .................................................................................
16.6. Psaní testů Seam bean ..........................................................................................
16.7. Jak testovat workflow ..............................................................................................
16.8. Pokrytí testy ...........................................................................................................
127
127
128
129
130
131
132
132
133
17. Nástroje
135
17.1. IdM Uploader .......................................................................................................... 135
vii
czechidm-progdoc
17.2. IdMKeyGenerator .................................................................................................... 135
17.3. JBPMSyntaxCheck ................................................................................................. 135
A. Revision History
137
Rejstřík
139
viii
Preface
1. Hlášení chyb
Jestliže naleznete chyby v tomto dokumentu nebo pokud máte nápad jak dokument vylepšit, rádi vás
vyslechneme. Prosíme zašlete zprávu na náš email [email protected]
ix
x
Struktura systému
1.1. Třívrstvá architektura
Při návrhu systému byla použita třívrstvá architektura. Aplikace se tedy skládá z následujících vrstev:
• Prezentační vrstvy, která zajišťuje interakci s uživatelem. Systém může implementovat více
různých prezentačních vrstev, například v podobě webového rozhraní nebo třeba v podobě
Java aplikace. Byly vytvořeny dvě nezávislé implementace webového rozhraní. Jedno rozhraní
je určeno administrátorům a druhé je pro obyčejné uživatele. Úplným oddělením těchto dvou
rozhraní předcházíme nechtěné situaci, kdy uživatel pracuje z daty, která jsou určena pouze
administrátorům. Kromě webového rozhraní poskytuje CzechIdM i webovou službu.
• Aplikační vrstvy, která implementuje business logiku systému. V této vrstvě se nachází veškerý
výkonný kód aplikace, například provisioning, synchronizace, workflows, atd. Aplikační vrstva
je z velké části tvořena právě pravidly a workflow, což jsou externí programy napsané v jazyce
BeanShell, uchovávané v datovém úložišti. Výhodou tohoto přístupu je jejich snadná údržba; je-li
potřeba nějaká změna v běžícím CzechIdM, stačí upravit konkrétní workflow nebo pravidlo, aniž by
bylo nutné provádět build na celé řešení.
• Datové vrstvy, která slouží pro ukládání a načítání dat z a do trvalého úložiště neboli repository. Tato
vrstva odstiňuje aplikační vrstvu od použitého datového úložiště. Tím může být libovolná relační
databáze.
Mezi vrstvami se data předávají v podobě DTO (Data Transfer Object) objektů. Zvažován byt
také způsob předávání dat pomocí J2EE Entit. To jsou objekty, se kterými pracuje vrstva datová.
Zapouzdřují data jednoho záznamu z nějaké tabulky databáze. Naproti tomu DTO je obyčejný Java
objekt obsahující pouze ty atributy, které ostatní vrstvy potřebují.
Tento přístup má oproti předávání Entit následující výhody:
• úplná nezávislost vrstev
• v DTO nejsou obsažena žádná interní data. Jedinou výjimkou je atribut version obsahující informaci
o verzi Entity, ze které byl DTO vytvořen. Ten bude pouze pro čtení a i v případě jeho změny
nemůže dojít k nekonzistentnosti.
• kontrola komunikace s databázi. Nejsou žádná volání databáze z prezentační vrstvy pro "dotažení"
dalších objektů. Tím nemůže dojít k jinak velmi časté lazy loading exception.
• v rámci datové vrstvy se DTO vyskytují pouze v rozhraní, která jsou určena pro komunikaci
s vrstvou aplikační. Pro komunikaci mezi jednotlivými moduly uvnitř datové vrstvy mohou být
používány přímo Entity.
1
Kapitola 1. Struktura systému
Obrázek 1.1. Třívrstvá architektura
1.2. Moduly a jejich topologie
Každá vrstva popsaná v předchozí kapitole je dále rozdělena na moduly. Moduly jsou navzájem
odděleny na úrovni adresářové struktury, v níž každému modulu odpovídá jeden adresář
(s případnými podadresáři). Toto rozdělení slouží především k lepší čitelnosti a celkové správě
zdrojového kódu. Rozvržení se také promítlo do webového rozhraní, a to v podobě položek v hlavním
menu.
Moduly prezentační vrstvy obsahují především xhtml, css soubory a obrázky. Dále pak JSF managed
beany, které slouží jako action listenery a upravují data do podoby vhodné pro prezentaci ve webovém
rozhraní. Kontrolují také navigaci mezi stránkami.
Moduly webové (prezentační) vrstvy:
Adresář
Popis
admin/authentication
Obsahuje přihlašovací stránku do administračního rozhraní.
admin/configuration
Zde jsou umístěny stránky konfigurace. Jedná se především o
vylistování, zobrazení, editace workflow, pravidel a emailových
šablon.
admin/help
Adresář pro stránky s nápovědou. Nápověda je v podadresářích s
kódem jazyka. Například "cs" a "en".
admin/layout
Zde je xhtml pro menu a základní šablona pro vzhled
administračního rozhraní.
admin/policy
Obsahuje formuláře pro vylistování, zobrazení a editaci politik
hesel.
admin/report
Adresář se stránkami pro reporty.
admin/role
Obsahuje formuláře pro vylistování, zobrazení a editaci rolí.
admin/system
Obsahuje formuláře pro vylistování, zobrazení a editaci koncových
systémů.
admin/task
Obsahuje formuláře pro vylistování, zobrazení a editaci
naplánovaných (pravidelně spouštěných) úloh.
2
Moduly a jejich topologie
Adresář
Popis
admin/user
Obsahuje formuláře potřebné pro správu uživatelů.
admin/userTask
Adresář se stránkami pro vylistování a zobrazení detailu
uživatelských úkolů (schvalování).
admin/workflow
Obsahuje stránky na zobrazení seznamu worfklow s možností
jejich spuštění.
img
Obsahuje loga, iconky a další obrázky.
include
Obsahuje xhtml, které se vkládají do více různých stránek.
js
Adresář obsahující soubory s javascripty.
stylesheets
Zde jsou umístěny kaskádové styly pro stránky i některé
komponenty.
user/authentication
Adresář s přihlašovací stránkou do uživatelského rozhraní.
user/help
Adresář pro stránky s nápovědou v uživatelském rozhraní.
Nápověda je v podadresářích s kódem jazyka. Například "cs" a
"en".
user/layout
Zde je xhtml pro menu a základní šablona pro vzhled
uživatelského rozhraní.
user/password
Obsahuje stránku pro změnu vlastního hesla v uživatelském
rozhraní.
user/personal
Obsahuje stránky s přehledem osobních údajů a přidělenách rolí.
user/settings
V tomto adresáři jsou formuláře, na kterých si uživatel může
nastavit webové rozhraní.
user/userTask
Adresář se stránkami pro vylistování a zobrazení detailu
uživatelských úkolů (schvalování).
Tabulka 1.1. Adresáře
Moduly aplikační vrstvy jsou implementovány pomocí Enterprise Java Beans. Tato vrstva je navržena
tak, aby bylo možné budoucí umístění některých jejích modulů na jiný server. Půjde zejména
o moduly, u kterých se dá předpokládat velká výpočetní náročnost, například modul synchronizace.
Mezi moduly v rámci této vrstvy jsou data předávána v podobě DTO získaných z vrstvy datové.
Balíček
Popis
...app.constant
Obsahuje message katalogy pro zprávy které, pochází z aplikační
vrstvy - tedy i z workflow a pravidel. Bude přesunuto do balíčku
eu.bcvsolutions.idm.app.i18n.
...app.core
Obsahuje třídy pro synchronizaci, provisioning a asynchronní
zpracování. V budoucnu bude pravděpodobně rozděleno do
samostatných balíků.
...app.email
Zde jsou třídy pro posílání emailů (zpracování emailové fronty).
...app.i18n
Obsahuje message katalogy pro zprávy které, pochází z aplikační
vrstvy - tedy i z workflow a pravidel.
...app.page
Zde jsou třídy sloužící jako prostředník s vrstvou prezentační.
...app.rule
V tomto balíčku jsou třídy pro spouštění pravidel.
...app.security
Jedná se o balíček zajišťující autentizaci a autorizaci.
3
Kapitola 1. Struktura systému
Balíček
Popis
...app.scheduler
Třída v tomto balíčku zodpovídá za spouštění pravidelných úloh.
...app.sso
Obsahuje servlet filter pro zajištění interakce s SSO agentem.
...app.user
Zde je především třída pro provisioning uživatelů na koncové
systémy. Ta je využívaná obecnou třídou z "core" balíčku.
...app.util
Pomocné třídy.
...app.workflow
Třídy rozšiřující a řídící workflow.
...app.ws
Balíček tříd pro webovou službu.
Tabulka 1.2. Balíčky
Následuje přehled modulů datové vrstvy. Jejich funkce jsou využívaný vesměs skrze fasádu v podobě
třídy "Data".
Balíček
Popis
...data.audit
Jsou zde třídy pro získávání auditních informací.
...data.configurations
Obsahuje třídy pro práci s nastavením CzechIdM uloženým v
repository.
...data.dto
V tomto balíčku jsou třídy reprezentující DTO. Tedy objekty
sloužící pro přenos dat mezi vrstvami.
...data.emailtemplate
Obsahuje třídy pro správu emailových šablon.
...data.entity
Zde jsou třídy reprezentující datový model (strukturu repository).
...data.lock
Obsahuje třídy, které zajišťují zamykání objektů.
...data.logging
Balíček tříd pro logování provozních i auditních záznamů do
repository.
...data.organisation
Obsahuje třídy pro správu organizací (organizačních jednotek).
...data.policy
Obsahuje třídy pro správu politik hesel.
...data.report
Obsahuje třídy pro správu reportů.
...data.resource
Obsahuje jednak třídy pro správu informací o koncových
systémech uložených v repository, ale také i třídy sloužící ke
komunikaci s connector frameworkem.
...data.resourcetype
Obsahuje třídy pro správu typů systémů.
...data.role
Obsahuje třídy pro správu rolí.
...data.rule
Obsahuje třídy pro správu pravidel.
...data.security
Třídy v tomto balíku slouží pro práci a autentizačními a
autorizačními informacemi uloženými v repository.
...data.scheduler
Obsahuje třídy, které plánovač využívá pro získávání a ukládání
dat o naplánovaných úlohách do repository.
...data.user
Obsahuje třídy pro správu uživatelů a částěčně i jejich účtů.
...data.usertask
Obsahuje třídy pro správu uživatelských úkolů (požadavků na
schválení).
...data.util
Pomocné třídy
4
Webové rozhraní
Balíček
Popis
...data.view
Obsahuje třídy reprezentující pohledy na různé objekty. Spolu s
DTO slouží pro předávání informací mezi vrstvami.
...data.workflow
Obsahuje třídy pro správu workflow.
Tabulka 1.3. Moduly datové vrstvy
1.3. Webové rozhraní
Uživatelské rozhraní je přístupné pomocí webového prohlížeče. Je vytvořeno pomocí XHTML stránek.
Jejich generování zajišťuje standardizovaný framework JSF (Java Server Faces) od firmy Sun
Microsystems. Při vývoji prezentační části aplikace jsme vycházeli z „Pravidel tvorby přístupného
webu“. (Tato pravidla byla napsána pro účely novely zákona č. 365/2000 Sb. o informačních
systémech veřejné správy, provedenou zákonem č. 81/2006 Sb.)
Výhodou přístupu k BCV IdM přes webové rozhraní je zejména to, že je aplikace uživatelům
i administrátorům přístupná z libovolného počítače, na kterém je nainstalován webový prohlížeč,
který má zapnutý JavaScript. Není tedy nutné na jednotlivé uživatelské stanice instalovat žádný další
software. Díky přístupu přes webové rozhraní navíc ani nezáleží na tom, jaký operační systém má
uživatel na počítači nainstalován.
Uživatelské rozhraní je rozděleno na dvě části – na část administrátorskou a na část uživatelskou.
Obě části mají podobný vzhled – ve svrchní části stránky se nachází vlevo logo zákazníka, vpravo
informace o aktuálně přihlášeném uživateli, následuje horizontální menu, ve střední a spodní části
stránky je blok se specifickými prvky (např. formuláře či tabulky) pro aktuálně zobrazenou stránku.
Tento blok obsahuje mimo jiné i lištu s ovládacími tlačítky, která se nachází ve vrchní i spodní části.
V uživatelském rozhraní zobrazuje IdM jen ty položky, na které má aktuálně přihlášený uživatel právo.
Uživatelské rozhraní je plně lokalizováno do českého a anglického jazyka. Jazykovou variantu si
uživatel zvolí při přihlášení nebo v nastavení svého účtu. Administrátorské rozhraní je lokalizováno do
českého jazyka.
1.3.1. Implementační detaily
Webové rozhraní je implementováno pomocí JavaServer Faces s využitím Facelets. Struktura
rozhraní je tedy definována sadou xhtml souborů.
Většina stránek (ty, které se obejdou bez nějaké speciální funkčnosti či bindigu) je obsluhována
jednou obecnou managed beanou GenericManagedBean. Ta je určena ke zpracování požadavků
vyvolaných ze stránky. Obsahuje dvě metody:
• processSubmit - nastaví kontext aktuálního workflow a tomu následně pošle signál pro přesun do
dalšího stavu.
• processEvent - provede mapování události na název workflow, nastaví jeho kontext a po té ho
spustí.
Pro práci s workflow slouží komponenta WorkflowControler. Vizte kapitolu Workflows.
Mapování událostí na názvy workflow stejně jako mapování na nazvy formulářu má na starosti
komponenta EventsMapping. Existuje ve scope application.
Kontext workflow je nastavován podle hodnoty atributu variables komponenty PageParameters. Ta
existuje ve scope Page.
5
Kapitola 1. Struktura systému
Typický proces zobrazení stránky a zpracování na ní umístěném formuláře vypadá následovně:
1. Běžící workflow vyvolá akci ShowPageAction, čímž dojde k jeho pozastavení
2. Je spuštěna metoda ShowPageAction.execute. Ta získá, případně vytvoří komponentu
PageParameters a do atributu variables nakopíruje obsah kontextu workflow. Případně může
přidat nějaké zprávy různého typu (info, error, warning, ...). Poté za pomoci komponenty
EventsMapping zjistí název stránky, která se má zobrazit. Pomocí třídy Redirect tuto stránku
zobrazí.
3. Uživatel edituje formulář na zobrazené stránce. Hodnoty jsou získávány a nastavovány
v komponentě PageParameters (buď přímo nebo prostřednictvím managed beany
stránky). Po stisknutí tlačítka pro odeslání formuláře bude obvykle zavolána metoda
GenericManagedBean.processSubmit.
4. Metoda processSubmit přetransformuje data a pomocí komponenty WorkflowControler nastaví
kontext čekajícího workflow a následně mu pošle signál pro přechod do dalšího stavu.
1.3.2. Repository
Pojmem repository se označuje úložiště interních informací IdM. BCV IdM ukládá svá data do relační
databáze, která podporuje JDBC protokol.
Mezi interní informace patří především:
• informace o identitách - v repository je uloženo minimum těchto informací. Většina je ponechána na
koncových systémech. Tím je zabráněno zbytečné redundanci a nekonzistentnosti mezi repository
a koncovým systémem
• informace o koncových systémech
• auditní logy
• definice workflow a pravidel
• archivy výsledků reportů, workflow, ...
• konfigurace
• jBPM informace
Pro práci s repositorý je použit ORM framework Hibernate (jedna z implementací JPA). Ten umožnuje
pracovat s relačními daty stejným způsobem, jako se pracuje s objekty. Pole jednoho (případně více)
záznamu v databázové tabulce jsou tak mapovány na atributy objektu, který se v tomto kontextu
nazývá Entita.
Některé entity obsahují:
• podpis - pro kontrolu neoprávněné změny
• zámek - pro kontrolu konkurenčního přístupu
• auditní atributy
Toto je implementováno pomocí hierarchie tříd
• SignedEntity - obsahuje atribut sign typu String
6
Použité technologie
• LockableEntity - rozšiřuje třídu SignedEntity o atribut lock typu DateTime
• AuditedEntity - rozšiřuje třídu LockableEntity o auditní atributy
Každá entita, která potřebuje jednu z výše uvedených funkčností, dědí od odpovídající třídy. Existuje
několik způsobů, jak lze inheritenci promítnout do struktury databázové tabulky. My používáme
způsob InheritanceType.TABLE_PER_CLASS, který atributy předků umístí do stejné tabulky společně
s atributy entity.
V databázi jsou tabulky, které odpovídají entitám znázorněných v diagramu konceptuálního modelu,
a tabulky, které pro svůj běh potřebuje jBPM.
1.3.3. Použité technologie
Systém je postaven na JEE 5.0 technologiích:
Komponenta
Verze
Popis
JavaServer Faces (JSF) http://
java.sun.com/javaee/javaserverfaces/
1.2
framework od společnosti Sun určený pro
vytváření webového rozhraní
Enterprise Java Beans (EJB) http://
java.sun.com/products/ejb/index.jsp
3.0
komponentová architektura pro vytváření
business vrstvy enterprise aplikací na
platformě Java. Je to standardní způsob
vytváření distribuovaných, transakčních,
bezpečných a přenositelných aplikací.
Komponenta
Verze
Popis
JBoss Seam Framework http://
seamframework.org/
2.2.0
Integrační framework kombinující
především JSF a EJB.
JBoss Hibernate http://www.hibernate.org/
3.x
Framework pro Object-relational mapping
(ORM). Implementace Java Persistance
API
JBoss jBPM http://www.jboss.org/jbpm
3.x
Business Process Management (BPM)
Suite. Technologie pro vytváření a správu
procesů
Identity Connectors Framework and Toolkit
https://identityconnectors.dev. java.net/
1.0
Technologie pro používaní a vytváření
konektorů, které slouží pro přípojení
a komunikaci s externími systémy
BeanShell http://www.beanshell.org/
2.0b4
Interpreter zdrojového kódu Javy
s podporou skriptování
TestNG http://testng.org/
5.9
Framework určený pro testování aplikace
Apache log4j http://logging.apache.org/
log4j/ 1.2/index.html
1.2
Nástroj pro vytváření logů
Tabulka 1.4. JEE technologie
Další používané technologie:
Tabulka 1.5. Další technologie
Komponenta
Verze
Popis
JBoss AS http://www.jboss.org/
jbossas
5.1.0
Aplikační server pro deploy IdM
7
Kapitola 1. Struktura systému
Komponenta
Verze
Popis
MySQL http://www.mysql.com/
5
Databázový server, který bude
používán pro uložení repository
IdM
Tabulka 1.6. Servery
8
Aplikační vrstva
2.1. Přihlašování
O přihlášení uživatele do CzechIdM se stará klíčová třída Authenticator, v níž dojde k ověření
uživatelského jména a hesla. Jméno a zadané heslo je nejprve načteno z credentials a následně
je (podle toho, zda se uživatel snaží přihlásit do administrátorského, nebo uživatelského rozhraní)
zavolána metoda authenticateIdentity na třídě Data s parametrem pro administrátorské nebo
běžné uživatelské rozhraní.
CzechIdM umožňuje přihlašování přes single sign-on. Tuto možnost je možné povolit nebo zakázat
v konfiguračním souboru (viz kapitolu "Konfigurace"). V případě, že sso není používáno, dojde k
porovnání hesla třídou SecurityManagementBean
CzechIdM umožňuje přihlašování proti heslu v repository, nebo proti heslu na koncovém systému.
Obvyklé je přihlašování proti heslu v repository; zde se ovšem neporovnávají plná hesla; z důvodu
bezpečnosti jsou v repository uloženy pouze jejich otisky. Je-li tedy v repository nalezena identita s
příslušným uživatelským jménem a otiskem hesla, je její totožnost považována za ověřenou a uživateli
je umožněn přístup do uživatelského nebo administrátorského rozhraní.
V některých situacích může být výhodné ověřovat identitu pomocí hesla v některém koncovém
systému, například v centrálním LDAPu. Tuto možnost je třeba před spuštěním aplikačního serveru
stanovit v konfiguračním souboru idm_configuration.properties. Konkrétně je zde třeba
nastavit properties "auth_resource" na název systému, vůči němuž má proběhnout autentizace,
"auth_schema" na schéma na tomto systému a "auth_id_attribute" na název atributu, který obsahuje
identifikátor účtu (viz též kapitolu Konfigurace). Jsou-li tyto tři properties korektně nastaveny, probíhá
přihlašování automaticky vůči zvolenému koncovému systému metodou authenticate v konektoru.
Uživatel se přihlašuje svým běžným uživatelským jménem v CzechIdM. Nejprve proběhne autentizace
proti nastavenému koncovému systému. Pokud neproběhne úspěšně, CzechIdM se může pokusit
autentizovat uživatele vůči otisku hesla ve své repository. Toto chování je nutné explicitně zapnout
nastavením atributu "auth_also_with_repository" na hodnotu "true". To pak umožní přihlášení
například identitám - administrátorům CzechIdM, kteří nemají žádné účty na koncových systémech.
# Fill in the resource name as defined in CzechIdM (e.g. Unix LDAP)
auth_resource=Portal
# Fill in the schema name as defined in CzechIdM (e.g. default)
auth_schema=default
# Fill in the name of the attribute, which holds identifier used by connector as Uid (e.g.
loginName)
auth_id_attribute=loginName
#This flag is taken into consideration if and only if a remote system authentication is
configured.
auth_also_with_repository=true
Po technické stránce je autentizace proti koncovému systému realizována v metodě
authenticateInRemoteResource na třídě Data. Ta volá metodu authenticate na třídě
ResourceManagementBean, ve které proběhne samotné ověření proti konektoru. V případě, že
konektor po zavolání příslušné metody authenticate vrátí uid daného uživatele, autentizace
úspěšně proběhla.
9
Kapitola 2. Aplikační vrstva
try {
if (checkPassword) {
Uid uid = connection.connector.authenticate(ObjectClass.ACCOUNT, name, new
GuardedString(password.toCharArray()), null);
if (uid != null) {
result = true;
}
} else {
ConnectorObject accountObj = connection.connector.getObject(ObjectClass.ACCOUNT, new
Uid(name), null);
if (accountObj != null) {
result = true;
}
}
} catch (RuntimeException e) {
result = false;
}
2.2. Workflow, pravidla a e-mailové šablony
Aplikační vrstva CzechIdM je tvořena kromě několika obecných tříd v aplikačních modulech zejména
sadou workflow, pravidel a e-mailových šablon. Workflow a pravidlům jsou v této dokumentaci
věnovány zvláštní kapitoly. V nich je popsáno, jak workflow a pravidla fungují a jak je vytvářet.
Workflow jsou základním stavebním kamenem aplikační vrstvy, nějaké workflow je spuštěno za
každým formulářem, každou zobrazenou stránkou a naprostou většinou akcí nad koncovými systémy,
identitami a rolemi.
2.2.1. Předávání proměnných mezi procesy
O spouštění workflow se stará třída
eu.bcvsolutions.idm.app.workflow.WorkflowControlerBean. Spuštěné workflow je
potom reprezentováno třídou eu.bcvsolutions.idm.app.workflow.WorkflowInstance.
Každé instance této třídy udržuje proměnné v proměnné variables, z ostatních tříd je možné tyto
proměnné získat nebo nastavit metodami getVariables() a setVariables().
V běžícím procesu jsou aktuální proměnné drženy v instanci třídy ContextInstance.
Třída WorkflowInstance synchronizuje své proměnné právě s proměnnými v instanci
ContextInstance, z níž lze proměnné získat metodou getVariables(). Proměnné jsou
předávány právě tímto kontextem a lze si je představit jako mapu Map<String,Object>.
Nastavení proměnných pro workflow zajišťuje třída WorkflowControllerBean, která
ve své metodě createWorkflow() na základě definice workflow parsováním xml
vytvoří novou instanci WorkflowInstance a nastaví proměnné pomocí statické metody
createFromWorkflowDefinition na třídě WorkflowInstance. Případné spouštění podprocesu
z workflow je podrobně popsáno v kapitole Workflow pomocí metod na třídě Application nebo
přímo coby subprocesu definovaného v jPDl.
Podobně jako workflow jsou aplikační vrstvou spouštěna pravidla. Správu pravidel má na starost třída
RuleControlerBean. Na rozdíl od workflow však při provádění pravidel není na základě definice
vytvořena žádná instance reprezentující pravidlo, ale je spuštěn interpreter bsh.Interpreter, který
provede přímo příkazy uvedené ve zdrojovém souboru.
10
Bussiness konstanty
2.3. Bussiness konstanty
Chod CzechIdM je možné konfigurovat pomocí takzvaných "bussiness" konstant. Jsou to konstanty
definované pro konkrétní nasazení CzechIdM, mohou obsahovat například délku karantény, některé
přihlašovací údaje k jednotlivým koncovým systémům nebo názvy specifických extended atributů.
Nejde tak o konfiguraci v obvyklém slova smyslu, jde o konstanty, které by v jiném nasazení zpravidla
vůbec nebyly definovány.
O načítání bussiness konstant se stará pravidlo getBusinessConstants. V něm je vytvořena mapa
konstant, do které může zasahovat administrátor. Tyto konstanty jsou poté přes své klíče dostupné ze
všech workflow i pravidel.
HashMap result = new HashMap();
result.put("ROLE_ATTR_PARENT", "parentDirPath");
// Perioda eskalace (bussiness kalendář lze upravit v konfiguračním souboru jbpm.cfg.xml)
// Ve workflow a pravidlech lze odted pracovat s konstantou ESCALATION_PERIOD, ma pevnou
retezcovou hodnotu "30 days".
result.put("ESCALATION_PERIOD", "30 days");
2.4. Pravidlo getExtendedAttributesNames
V pravidle getExtendedAttributesNames je definována mapa extended atributů a jejich typů. To je
výhodné zejména pro zobrazování extended atributů v administrátorském rozhraní. Aplikace pomocí
pravidla nalezne typ atributu a je schopna ho přijatelným způsobem formátovat.
2.5. Modul Utils
Modul eu.bcvsolutions.idm.app.util obsahuje pomocné metody pro práci v aplikační vrstvě. Konkrétně
jde především o samotnou třídu Utils, ve které lze najít sadu užitečných metod pro práci s view,
s atributy koncových systémů, s extended atributy nebo některé často používané metody pro
formátování. Do této třídy by měly být přidávány všechny metody, které mají pro pravidla a workflow
pomocnou funkci a je pravděpodobné, že budou volány z mnoha různých míst v aplikační vrstvě.
11
12
Datová vrstva
3.1. Entity
CzechIdM uchovává informace o identitách, rolích, atributech na účtech, organizacích atd. pomocí
technologie Hibernate, která umožňuje mapovat jednotlivé instance objektů přímo na řádky tabulky
v databázi. Atributy objektů jsou v kódu označeny příslušnými Hibernate anotacemi, s jejichž pomocí
je Hibernate mapuje do hodnot jednotlivých sloupců. Třída, jejíž instance jsou takto uchovávány,
se nazývá entita. Příkladem takové entity mohou být naříklad třídy Identity nebo Role. Anotace
@Entity říká, že tato entita bude ukládána do repository, anotace @Table určuje, do které tabulky
budou entity ukládány, anotací @NamedQueries lze specifikovat některé předchystané query.
@Entity
@Table(name = "roles")
@NamedQueries({
@NamedQuery(
name = "Role.selectByName",
query = "SELECT r FROM Role AS r WHERE r.name = :name"
)
})
public class Role extends AbstractRole {
...
}
3.1.1. Hierarchie entit
Všechny entity v CzechIdM dědí od jednoho společného předka IdmEntity. Na něm je definován
jedinečný identifikátor entityId, kterým lze odlišit dvě libovolné entity v CzechIdM. Pomocí tohoto
identifikátoru jsou také implementovány relační extended atributy.
Další důležitou nadtřídou některých entit je třída ViewMainEntity, jejíž potomci jsou ty třídy,
na jejichž základě vzniká nějaké view. View je datový objekt, obsahující informace o entitě, který
poskytuje datová vrstva vrstvě aplikační. Od této entity dědí právě například Identity nebo Role.
Je-li navíc entita potomkem třídy AuditedEntity, jsou u každého záznamu dané entity logovány
i informace o tom, kdo ji vytvořil, modifikoval a kdy se tak stalo. Sama tato třída dědí od třídy
SignedEntity, která uchovává heš svých atributů, a není tedy možné neoprávněně měnit její
atributy. Tím je zajištěna pravost a nepopiratelnost záznamů v auditním logu. Heš je počítána funkcí
SHA na třídě SecurityUtils.
3.1.2. View
Rozhraní View slouží k předání informací mezi datovou a aplikační vrstvou. Pohledy implementují
návrhový vzor DTO a jsou vytvářeny pro přenos dat určitého typu. Za tímto účelem mohou byt
rozšířeny o atributy specifické pro daný typ dat. Jako příklad poslouží nejdůležitější pohled a to
UserView. Ten seskupuje nejen informace o identitě dostupné z repository, ale i data z příslušných
účtů na koncových systémech. Návíce je UserView rozšířené o atributy, jejichž hodnoty mění způsob
zpracování tototo pohledu. Důvodem k použití View je především zjednodušení práce s daty ve
workflow a pravidlech. Na pohled se lze totiž dívat jako na jednoduchou mapu, která sdružuje
13
Kapitola 3. Datová vrstva
informace logicky k sobě náležející. Dalším důvodem je, stejně jako u jiných DTO, bezpečnost. Ke
skutečným datům v repository se přistupuje jen z několika tříd v datové vrstvě. Aplikační vrstva smí
modifikovat pouze tyto "pohledy", a nemá tak přímý přístup k databázi.
Aplikační vrstva má možnost přistupovat k pohledům na identity přes statické metody na třídě Data:
metody checkoutView a checkinView. O těchto metodách podrobněji pojednávají další odstavce v
této sekci.
3.2. Obecné třídy uchovávající data
3.2.1. DTOModifiable <T>
Rozhraní představující datovou strukturu, která uchovává informace o změnách v datech. Je
parametrizováno typem T, v němž je zachycena informace o změně. Změnu lze získat veřejnou
metodou T getModification(). Jeho potomkem je rozhraní DTO.
3.2.2. DTO
Rozhraní, které představuje modifikovatelnou datovou strukturu, v níž jsou data uchovávána
v mapě jako dvojice "klíč - hodnota". Dědí od rozhraní DTOModifiable <Map<String,
DTOModification>>, je implementováno třídou DTOGroup.
Jednotlivá DTO lze vnořovat, hodnotou pro daný klíč může být opět DTO. V takovém případě je
změna ve vnořeném DTO chápána jako změna rodičovského DTO. Z jednotlivých instancí DTO
je možné sestavovat složitější stromové struktury. Přístup k jednotlivým hodnotám ve stromové
struktuře, jíž je dané DTO kořenem, umožňují metody Serializable get(String[] path)
a void put(String[] path, Object value). Parametrem path se rozumí cesta po
jednotlivých klíčích do zanořených DTO. Zda taková cesta existuje, lze ověřit metodou boolean
containsPath(String[] path). V případě, že je zavolána metoda put a zadaná cesta
neexistuje, jsou vytvořena nová DTO a chybějící úsek cesty je nově vybudován.
Rozhraní DTO je v CzechIdM rodičovským rozhraním pro View, které implementují ostatní view jako
například GenericView.
3.2.3. DTOModification
Třída reprezentující jednu změnu v DTO pro konkrétní klíč. Obsahuje tři důležité atributy:
• Serializable oldValue - hodnota pro daný klíč před modifikací
• Serializable newValue - hodnota pro daný klíč po modifikaci
• Type type - druh změny, jedná se o výčtový typ, který může nabývat hodnot ADD, REMOVE a
CHANGE
3.2.4. DTOGroup
Třída implementující DTO pomocí hešovací mapy. Zjišťování modifikací dané DTOGroup probíhá v
implementacích následujícím způsobem:
1. Vytvoří se nová prázdná výstupní mapa "klíč - modifikace"
2. Zjistí se modifikace pro konkrétní klíče tohoto DTO a zařadí se do výstupní mapy
14
DTOList<E>
3. Je-li některá z hodnot implementací DTOModifiable, zjistí se její modifikace metodou
getModification()
4. Pokud je taková hodnota modifikována (getModification() vrátilo neprázdnou kolekci,
neprázdnou mapu nebo jiný objekt, který není null), zařadí se do výstupní mapy pro příslušný
klíč modifikaci typu CHANGE
5. Vrátí se výstupní mapa.
Změny ve vnořených DTOGroup se tedy nepropagují do rodičovských DTOGroup v okamžiku, kdy
k nim dojde, ale zjišťují se teprve v okamžiku, kde je na rodičovské DTOGroup zavolána metoda
getModification(). Není proto efektivní volat tuto metodu opakovaně, pokud je pravděpodobné,
že od posledního volání nedošlo k žádné změně.
Informace o zaznamenaných modifikacích lze odstranit metodou clearModification().
V CzechIdM je DTOGroup rodičovskou třídou GenericView, což je abstraktní třída, od níž dědí
ostatní view jako například UserView.
3.2.5. DTOList<E>
Rozhraní rozšiřující DTOModifiable<Map<E, Integer>>. Představuje datovou strukturu, v níž
jsou data uchovávána ve formě seznamu a je ukládána informace o proběhlých změnách. K metodám
z DTOModifiable přidává metody z List a metody List<E> getAddedElements() a List<E>
getRemovedElements(), kterými lze získat informace o přidaných a odebraných prvcích.
3.2.6. DTOLinkedList<E>
Implementuje DTOList<E> pomocí spojového seznamu. Ve formě DTOLinkedList je v CzechIdM
uchováván například seznam rolí dané identity.
3.2.7. View
Rozhraní, které reprezentuje obecný pohled na nějakou entitu v CzechIdM. Poskytuje základní obecné
informace o daném pohledu ve formě mapy, která udržuje atributy jako dvojice klíč-hodnota.
3.2.8. GenericView
Abstraktní třída, která implementuje základní metody z rozhraní View. Dědí od ní velká většina
ostatních view.
3.2.9. UserView
Třída reprezentující pohled na jednu identitu v CzechIdM. Dědí od třídy GenericView. Atributy o
identitě jsou uchovávány jako dvojice "klíč - hodnota", název a popis atributu je v tabulce:
name
Celé jméno identity. Slouží jako identifikátor.
firstName
Křestní jméno
lastName
Příjmení
disabled
Příznak toho, že je identita zablokována.
15
Kapitola 3. Datová vrstva
password
Heslo. Po checkoutu je vždy null. Pokud má po
checkinu jinou hodnotu, heslo se změní.
idmManager
Atribut "name" nadřízeného nebo null, pokud
uživatel nemá nadřízeného.
attributes
Mapa entitních extended atributů; klíčem je
název atributu, hodnotou je hodnota atributu
homeOrganisation
Název organizace ve tvaru "top: .... :
nadOrganizace:organizace"
controledOrganisations
Seznam názvů kontrolovaných organizací ve
formátu "top: .... : nadOrganizace:organizace"
roles
Seznam názvů přidělených rolí
accounts
Mapa účtů. Klíčem je jméno resource, hodnotou
mapa schémat na daném resource. Klíčem v
mapě schémat je jméno schématu, hodnotou
mapa atributů daného schématu.
relationAttributes
Mapa relačních extended atributů. Pro přesnou
strukturu viz Extended atributy - návrh
Tabulka 3.1. Atributy UserView
3.2.10. Extended atributy
Do takzvaných "extended" atributů jsou v daném View ukládány informace, které souvisejí pouze
s konkrétním nasazením CzechIdM, ne s jeho obecnou podobou. Extended atributy v CzechIdM
existují dvojího druhu: "entitní" a "relační". Entitní extended atributy se vztahují přímo k jedné instanci
konkrétní entity (například tituly daného uživatele), zatímco relační se vztahují ke dvěma instancím
entit, které mohou být různé (například vztah identity k roli). V CzechIdM jsou oba druhy extended
atributů reprezentovány třídou ExtendedAttribute.
3.2.10.1. Návrh
Každý extended atribut je tvořen svým jménem a hodnotou. Tato hodnota musí být objekt
implementující rozhraní Serializable. V repository jsou všechny extended atributy uchovávány v
jediné tabulce extended_attributes. V ní lze nalézt sloupce popsané v následující tabulce:
atr_id
Jedinečný, automaticky generovaný identifikátor
extended atributu
name
Název atributu
value
Hodnota atributu (LOB), může obsahovat
libovolný serializovatelný objekt
valueAsString
Hodnota atributu převedená na řetězec metodou
toString().
owner_id
EntityId té entity, které atribut náleží
related_id
Entityid té entity, která je cílovou entitou relace.
Pokud je tedy atribut čistě entitní, je owner_id a
related_id stejné.
Tabulka 3.2. Sloupce tabulky extended_attributes
16
View handlery
Zda se jedná o atribut entitní, nebo relační, se rozhoduje na základě porovnání hodnot ve sloupcích
"owner_id" a "related_id". Jsou-li stejné, jde o entitní atribut, jinak relační.
Do view jsou extended atributy načítány metodou fillExtendedAttributes na
třídě GenericViewHandler. Tato metoda nejprve načte z repository všechny atributy,
které se týkají daného view, tedy ty, které se shodují alespon v owner_id s view, do
kterého je načítáno. Entitní atributy poté uloží do samostatné DTOGroup pod klíč
View.EXTENDED_ATTRIBUTES_ENTITY_KEY_NAME. Zařazení relačních atributů je složitější: pod
klíčem View.EXTENDED_ATTRIBUTES_RELATION_KEY_NAME je hodnotou další DTOGroup, v níž
jsou klíči entityId identifikátory konkrétních instancí entit. Hodnotou pro daný identifikátor je DTOGroup
obsahující ve tvaru "klíč-hodnota" extended atributy konkrétní relace.
Veškeré změny v extended atributech jsou po zavolání checkInView propagovány strukturou
DTOGroup jako změny celého view, a mohou tedy být zpracovány a pozměněny v repository.
3.2.10.2. Třída ExtendedAttribute
Třída reprezentující jeden entitní nebo relační extended atribut. Jednotlivé atributy jsou přímo
mapovány na sloupce tabulky v repository. Ke zjištění, zda je atribut relační, nebo entitní, slouží
metoda boolean isEntityExtAtr(), která vrací true, pokud je atribut entitním atributem.
Instance třídy ExtendedAttribute slouží pouze pro ukládání atributů do repository a pro jejich
opětovné načítání. V konkrétním view jsou extended atributy uchovávány výše popsaným způsobem
pomocí vnořených DTOGroup. K načtení všech extended atributů, které se týkají daného view,
slouží metoda List<ExtendedAttribute> getAllExtendedAttributes(EntityManager
entityManager) na třídě GenericView.
Sloupec valueAsString se dá použít při vyhledávání entit (uživatelů, organizací) pomocí extended
atributů, speciálně relací "Začíná na". Řetězec, který uživatel vyhledává, musí být totiž porovnáván s
hodnotou typu String.
3.3. View handlery
Vytváření a zpracovávání pohledů obstarávají v datové vrstvě takzvané view handler třídy. Jde o
implementace rozhraní ViewHandler. Pro každé konkrétní View (například UserView, RoleView, ...)
existuje samostatný ViewHandler (UserViewHandler, RoleViewHandler, ...). ViewHandlery dědí
od GenericViewHandler, který implementuje podpůrné metody využivané jeho potomky. Interface
ViewHandler deklaruje následující metody.
Uvedené metody jsou implementovány v konkrétních ViewHandlerech (dědících od
GenericViewHandleru).
3.3.1. Metoda ViewHandler.createEmptyView
Vytvoří prázdné view, které má správnou strukturu atributů s výchozími hodnotami. Aplikační vrstva
volá tuhle metodu pomocí metody "createEmptyView" na třídě "Data".
3.3.2. Metoda ViewHandler.createView
Metoda, která vytvoří pohled na základě již existujících dat v repository, případně i koncových
systémů. Z aplikační vstvy opět voláno přes metody (checkoutView, getReadOnlyView, ...) třídy
"Data".
17
Kapitola 3. Datová vrstva
3.3.3. Metoda ViewHandler.processViewChanges
Metoda, která zpracuje dodané view. To znamená, že upraví nebo vytvoří potřebné entity v repository.
Také může připravit hodnoty ve view k jejich propagaci na koncové systémy (samotná změna dat na
koncových systémech proběhne v provisioningu).
3.4. Třída Data
Tahle třída zpřístupňuje aplikační vrstvě většinu funkcí vrstvy datové. Všechny metody jsou statické.
3.4.1. Získání pohledu na existující entitu - metoda
Data.checkoutView
Aplikační vrstva CzechIdM nepracuje přímo s entitami uloženými v databázi, ale pouze s pohledy
(view) na tyto entity. Pohledy jsou v CzechIdM reprezentovány implementacemi rozhraní View. Pro
získání pohledu na konkrétní entitu slouží na třídě Data statická metoda checkoutView. Jejím
prvním parametrem je typ view, které má být vráceno, druhým parametrem potom identifikátor entity,
kterého se view má týkat.
Po zavolání checkoutView je příslušná entita uzamčena a není možné na ní provádět změny. Proto
je nezbytné po provedení změn na pohledu zámek odstranit buď metodou checkinView, při níž se
zpracují i všechny provedené změny, anebo metodou releaseViewLock, která pouze uvolní zámek
a změny nezpracuje. Pokud je tedy požadován pohled, na němž nebudou prováděny žádné změny,
je výhodnější zavolat metodu, která vrací view pouze pro čtení: getReadOnlyView na třídě Data.
Další metodou, která vrací pohled na entitu, je metoda checkoutTrimmedView. Ta však vrací pouze
"ořezaný" pohled, který neobsahuje data nacházející se mimo repository. Její zavolání je rychlé, ale
výsledek neobsahuje všechny informace.
3.4.1.1. Získání příslušného managementu
S různými entitami v CzechIdM mohou pracovat různé implementace rozhraní DataManagement.
V úvodu metody je proto na základě typu view získána příslušná implementace (pro UserView je
to například UserManagementBean. Obecné metody většiny těchto tříd jsou implementovány již
ve společné abstraktní nadtřídě GenericDataManagement. Na získané třídě je poté zavolána
metoda retrieveView. Ta je implementována na třídě GenericDataManagement a většina jejích
podtříd využívá této obecné implementace. Na začátku metody retrieveView je ověřeno, zda má
uživatel práva k získání pohledu. Pokud ano, je pohled získán pomocí třídy implementující rozhraní
ViewHandler pro daný typ pohledu (například UserViewHandler, RoleViewHandler,...). Velká
část implementací ViewHandler je potomkem obecné abstraktní třídy GenericViewHandler a využívá
některé její metody.
3.4.1.2. Metoda createView v rozhraní ViewHandler
Metoda createView v rozhraní ViewHandler slouží k vytvoření pohledu na entitu zadanou v
prvním parametru. Je implementována v třídách pro konkrétní typy pohledů. Příkladem metody bude
metoda na třídě UserViewHandler, které se bude věnovat další odstavec.
3.4.1.3. Vytvoření pohledu na identitu
K získání pohledu na identitu slouží uvnitř datové vrstvy třída UserViewHandler. V tomto odstavci
bude popsán průběh vytváření pohledu na již existující identitu:
1. Vytvoření prázdného UserView.
18
Získání pohledu pro čtení na existující entitu - metoda Data.getReadOnlyView
2. Načtení domovské organizace a organizací kontrolovaných na základě atributů identity
3. Nastavení atributu hesla v pohledu na null: v databázi jsou uloženy pouze otisky hesla, které
nemají pro aplikační vrstvu žádný význam. Bude-li při checkinView v tomto atributu jiné
nenulové heslo, proběhne změna hesla.
4. Načtení atributu vedoucího: do atributu je uloženo jméno té identity, která je u identity, na niž je
vytvářen pohled, uvedena jako vedoucí.
5. Načtení extended atributů: k načtení extended atributů do View slouží obecná metoda
fillExtendedAttributes na třídě GenericViewHandler. Extended atributům je věnována
samostatná sekce v kapitole o datové vrstvě.
6. Načtení přiřazených rolí na základě rolí uvedených u identity
7. Načtení informací o účtech. Struktura informací o jednotlivých účtech je blíže popsána v sekci
týkající se UserView
3.4.2. Získání pohledu pro čtení na existující entitu - metoda
Data.getReadOnlyView
Tato metoda má téměř identický průběh jako metoda Data.checkoutView. Rozdíly jsou pouze dva:
nastavení příznaku isreadonly na true, což způsobí, že provedené na tomto view nebude možné
propagovat zpět do datové vrstvy. Druhým rozdílem je, že identita, na níž je vytvořen pohled tohoto
typu, není uzamčena.
3.4.3. Získání ořezaného pohledu na existující entitu - metoda
Data.checkoutTrimmedView
Tato metoda má podobný průběh jako metoda Data.checkoutView. Výsledné View však
neobsahuje všechny informace, ale pouze ty, které byly dostupné přímo z repository. Její volání je tedy
výrazně rychlejší, ale výsledné View je ořezané, a lze tedy použít jen v některých situacích.
3.4.4. Zpracování změn ve View - metoda Data.checkinView
Aplikační vrstva CzechIdM nepracuje přímo s entitami, které jsou ukládány do repository. Pracuje
pouze s pohledy na tyto entity podle návrhového vzoru DTO. V CzechIdM jsou pohledy tvořeny
implementacemi rozhraní View. V aplikační vrstvě jsou informace o konkrétní entitě získány statickou
metodou Data.checkoutView(View.Type viewType, String id), která navrací pohled na
danou entitu (například roli, identitu, organizaci...). Na tomto pohledu mohou být následně prováděny
změny: uživateli mohou být například přiřazeny nové role nebo mu může být změněn nadřízený. V
okamžiku, kdy je práce s View skončena, musí být změny propagovány do úložiště a případně i na
koncové systémy. K tomu slouží statická metoda checkinView(View view) na třídě Data. V
následující sekci je podrobně popsán její průběh.
3.4.4.1. Získání příslušného managementu
S různými entitami v CzechIdM mohou pracovat různé implementace rozhraní DataManagement.
V úvodu metody je proto na základě typu view získána příslušná implementace (pro UserView je
to například UserManagementBean. Obecné metody většiny těchto tříd jsou implementovány již ve
společné abstraktní nadtřídě GenericDataManagement. Na získané třídě je poté zavolána metoda
19
Kapitola 3. Datová vrstva
saveView. Ta je implementována na třídě GenericDataManagement a většina jejích podtříd
využívá této obecné implementace.
3.4.4.2. Metoda saveView
Metoda saveView se skládá ze tří klíčových částí: Za prvé instrukcí, které mají být provedeny před
samotným uložením. Za druhé samotného uložení a nakonec z instrukcí, které mají být provedeny po
uložení.
Před uložením je na konkrétní implementace DataManagement zavolána metoda beforeSaveView.
Obecným chováním na třídě GenericDataManagement před uložením view je spuštění workflow
s názvem "{typ view}.before.checkin" (například "user.before.checkin"). V něm mohou být provedeny
akce, které jsou specifické pro konkrétní typ view. V již zmíněném workflow "user.before.checkin"
probíhá aktualizace účtů. Přesnému průběhu checkinView pro UserView je věnována samostatná
sekce.
Klíčovou metodou, v níž probíhá zpracování změn, je metoda processViewChanges z rozhraní
ViewHandler, v níž jsou podle typu view zaznamenány změny a aktualizována samotná entita a
případně i účty na koncových systémech.
Po uložení je zavolána metoda afterSaveView. Ta může být využita některými
implementacemi rozhraní DataManagement k provedení některých nutných akcí. Třída
SchedulerTaskManagement například využívá metodu afterSaveView k přenastavení časovače.
Na třídě GenericDataManagement je tato metoda prázdná.
3.4.4.3. Provisioning
Po aktualizování některých entit může být zapotřebí aktualizovat data na koncových systémech.
Pokud to konkrétní implementace ukládaného View podporuje, proběhne v tomto okamžiku
aktualizace pomocí metody doProvisioning na příslušné implementaci DataManagement.
3.4.4.4. Uvolnění zámku
Po skončení saveView a provisioningu je metodou releaseViewLock na příslušné implementaci
DataManagement uvolněn zámek na hlavní entitě daného view. Informace o entitě nyní mohou
upravovat další části aplikace.
3.4.5. Specifika metody Data.checkinView pro parametr typu
UserView
Metoda checkinView slouží ke zpracování změn, které provedla aplikační vrstva na pohledu na
danou identitu, a jejich propagování do repository a případně i na koncové systémy. V této sekci
jsou popsána specifika zpracování změn pohledu na identitu v CzechIdM, reprezentovaného třídou
UserView. Sekce se zejména zabývá konkrétními implementacemi některých obecných metod, pro
pochopení problematiky je tedy vhodné nejprve nahlédnout do sekcí týkajících se obecného postupu
při zavolání metody checkinView.
3.4.5.1. Workflow "user.before.checkin" v metodě beforeSaveView
Při zpracování změn pohledu na identitu, reprezentovaného instancí třídy UserView, je používána
třída UserManagement, která dědí od abstraktní třídy GenericDataManagement a využívá
některých jejích obecných metod. Jednou z nich je obecná varianta metody beforeSaveView, v
20
Specifika metody Data.checkinView pro parametr typu UserView
níž probíhají akce nezbytné před samotným uložením. Obecným chováním je spuštění workflow s
názvem "{typ view}.before.checkin", v našem případě tedy "user.before.checkin".
Uvnitř tohoto workflow je provedena jediná akce: pomocí metody
Data.updateAccountsFromIdentity jsou aktualizovány atributy na účtech, jejichž vlastníkem je
zpracovávaná identita. Aktualizací atributů účtů se zabývá samostatná sekce v kapitole o koncových
systémech.
3.4.5.2. Metoda processViewChanges na třídě UserViewHandler
Metoda processViewChanges na třídě UserViewHandler zpracovává změny na třídě UserView
a zajišťuje jejich správnou propagaci do samotné entity reprezentované třídou Identity a na koncové
systémy. Během metody probíhají následující fáze:
1. Zpracování rolí: jsou rozpoznány nově přiřazené role. Pro každou nově přiřazenou roli, která
má definovaného schvalovatele, je spuštěn schvalovací proces (název workflow je definován
konstantou Constants.ROLE_APPROVE_WF_NAME, zpravidla jako "user.role.approve"). Nově
přidané role jsou přidány do seznamu rolí u příslušné identity.
2. Zpracování základních atributů: jména identity, křestního jména, příjmení, e-mailu a příznaku
zablokování. Pozměněné atributy jsou přepsány u příslušné identity.
3. Zpracování hesla: nejprve je pomocí pravidla s názvem
Constants.CHECK_PASSWORD_RULE_NAME (zpravidla "checkPasswords") zkontrolováno, zda je
heslo řádně vyplněno. To znamená, zda jsou splněny následující podmínky:
• Je-li vyplněno jedno pole pro zadání hesla, musí být zadáno i druhé.
• Jsou-li obě pole pro zadání hesla vyplněna, musí se shodovat.
• Nejsou-li pole vyplněna, view nesmí být pohledem na nově vytvořeného uživatele.
Je-li kontrola ukončena a nejsou-li nalezeny žádné chyby, dojde ke změně hesla u identity. Staré
heslo je uloženo do historie hesel.
4. Zpracování vedoucího: Je ověřeno, zda zadaný vedoucí existuje, a změna, odebrání nebo přidání
vedoucího je zalogována do auditního logu. Změna vedoucího je propagována k identitě.
5. Zpracování extended atributů: UserViewHandler využívá obecnou metodu na třídě
GenericViewHandler. O extended atributech pojednává samostatná sekce v kapitole o datové
vrstvě.
6. Zpracování domovské organizace: změna organizace je zalogována do auditního logu a
propagována do identity.
7. Zpracování kontrolovaných organizací: nalezení entit organizací a propagace změn do identity.
8. Zpracování uživatelské konfigurace: zjištěny změny v jazykové variantě, počtu řádků v tabulkách a
podobně. Neexistuje-li zatím žádná konfigurace, je vytvořena nová, a změny jsou propagovány do
identity
9. Aktualizace účtů na koncových systémech na základě přiřazených rolí pomocí metody
actualizeAccountsFromRoles na třídě UserViewAttributesPropagator. Aktualizaci
účtů na koncových systémech je věnována samostatná sekce v kapitole o koncových systémech.
21
Kapitola 3. Datová vrstva
10. Ověření, zda nové heslo splňuje bezpečnostní politiku hesel pro všechna schémata, na nichž má
být heslo změněno.
11. Aktualizovaná identita je uložena do repository.
3.4.5.3. UserProvisioning
Součástí statické metody checkinView na třídě Data je aktualizace dat na koncových
systémech u těch pohledů, které podporují provisioning. Třída UserView provisioning
podporuje, je reprezentováno třídou UserProvisioning. Po spuštění UserProvisioning
proběhne provisioning účtů zvlášť pro každý koncový systém, o to se stará třída
OneResourceUserProvisioning. Součástí provisioningu je zejména vytvoření nového účtu,
odlinkování účtu, přilinkování účtu a další akce pracující s účtem a ne hodnotami jeho atributů.
3.4.6. Další užitečné metody na třídě Data
Potřebuje-li aplikační vrstva přistupovat k datovému podkladu, nečiní tak přímo, ale prostřednictvím
třídy Data. Třída Data nabízí aplikační vrstvě celou řadu užitečných statických metod.
3.4.6.1. Data.addRoleWithoutApprovement
Tato metoda zajistí přidělení role danému uživateli. Na rozdíl od běžného postupu však není
ověřováno, zda má role stanoveného nějakého schvalovatele, pomocí této metody lze přiřadit roli
bez schválení. Jelikož některé role opravňují k přístupu na koncové systémy, nebo jsou jimi počítány
atributy na účtech, probíhá na konci této metody provisioning účtů.
3.4.6.2. Data.delete
Pomocí metody delete lze dosáhnout smazání entity v repository (například role, identity...). Za
některých okolností však metoda delete nebude účinkovat, například při pokusu o smazání role,
která je přiřazena některému uživateli. Metoda vrací hodnotu boolean podle toho, zda se podařilo
entitu úspěšně smazat.
3.4.6.3. Data.getEntityId
V CzechIdM má každá entita několik identifikátorů. Obvyklý identifikátor, který se používá například při
metodě checkoutView, však není unikátní napříč všemi entitami v CzechIdM, a neidentifikuje proto
entitu jednoznačně. Proto byl zaveden druhý identifikátor označovaný entityId, který je unikátní
napříč všemi entitami v CzechIdM. Metoda popisovaná v tomto odstavci umožňuje snadno získat
entityId, známe-li běžný identifikátor a typ entity. EntityId je používáno především pro relační
extended atributy. Právě entityId je klíčem v mapě relačních extended atributů.
3.4.6.4. Data.getLoggedUserName
Metoda getLoggedUserName na třídě Data navrací uživatelské jméno právě přihlášeného uživatele.
Je užitečná při vytváření workflow; například v situaci, kdy je nutné ověřit, zda má právě přihlášený
uživatel právo na akci, která proběhne spuštěním workflow.
3.4.6.5. Data.getSchemaId
Každé schéma na koncovém systému má svůj vlastní identifikátor, který je jedinečný napříč všemi
schématy v jedné instanci CzechIdM. Schéma lze ovšem také identifikovat dvojicí "název resource",
"název schématu". Metoda getSchemaId slouží k převodu dvojice názvů na identifikátor schématu.
22
Criteria
3.4.6.6. Data.listIds
Metoda listIds navrací seznam identifikátorů všech entit daného typu, které vyhovují stanoveným
kritériím. Může být tedy využita například v situaci, kdy potřebujeme provést akci pouze s těmi
uživateli, kteří mají nastavený extended atribut na stanovenou hodnotu.
3.4.6.7. Data.setUserAccountsEnabled
V jistých situacích může být užitečné zablokovat uživateli pouze některé účty, nikoli celý uživatelský
profil. K tomu slouží metoda popisovaná v tomto odstavci. Její třetí parametr udává, zda mají být účty
zablokovány, či odblokovány.
3.4.6.8. Data.listResourceSchemas
Vypíše identifikátory všech schémat na koncovém systému.
3.4.6.9. Data.deleteAccount
Tato metoda smaže uživatelský účet s daným identifikátorem na daném resource.
3.5. Criteria
Třída Criteria stanovuje kritérium výběru. Každá entita v CzechIdM tato kritéria splňuje, nebo
nesplňuje. Právě pomocí instance třídy Criteria je možné získat pouze entity s danou vlastností
(viz Data.listIds). Na instanci třídy Criteria lze nahlížet jako na klauzuli WHERE v jazyce SQL. Do
tohoto filtru lze přidávat podmínky, které jsou spojeny logickou spojkou AND.
V některých situacích může být výhodné použít takzvaný "alias", kterým lze porovnávání vztáhnout
i na některou entitu, s níž je porovnávaná entita v relaci. Chceme-li proto například stanovit kritéria,
která splnují všichni uživatelé, kteří mají extended atribut "valid" nastavený na "true", použijeme
následující kód. Vycházíme ze znalosti struktury dat; každá identita je ve vztahu 1:n k extended
atributům.
Criteria criteria = new Criteria();
criteria.createAlias("extendedAttributes", "attrs");
criteria.add("attrs.name", "valid", Relation.EQ);
criteria.addEq("attrs.value", true);
List idList = Data.listIds(View.Type.USER, criteria);
23
24
Prezentační vrstva
4.1. Použité technologie
Prezentační vrstva je založena na technologiích JavaServer Faces, Facelets a RichFaces. JavaServer
Faces je framework usnadňující vývoj uživatelských rozhraní JavaServer aplikací. Použitou verzí JSF
je 1.2. Tato verze používá primárně pro zobrazování JSF stránek uživateli technologii JavaServer
Pages. V tomto případě však byla použita technologie Facelets, což zjednodušuje a zpřehledňuje
samotný vývoj prezentační vrstvy. Podpora Ajaxu je zajištěna použitím knihoven projektu RichFaces.
4.2. Členění uživatelského rozhraní
Uživatelské rozhraní je rozděleno na dvě separátní části. První část je určena pro administrátory
systému, druhá část pro běžné uživatele. Po vizuální stránce jsou si obě rozhraní podobná. Hlavním
důvodem pro toto rozdělení je jednoduchost pro běžné uživatele. Dále je to i bezpečnost.
Administrátorské rozhraní nabízí širší možnosti správy CzechIdm, jako je správa uživatelů, rolí,
workflow a další, které obyčejný uživatel nepotřebuje.
Důležitou součástí jsou jBPM workflow, která jsou spouštěna po každém kliknutí na odkaz, submitnutí
tlačítka formuláře atd.
4.3. Třída GenericManagedBean
Třída GenericManagedBean slouží prezentační vrstvě k ovládání workflow, která jsou asociována
s právě zobrazenou stránkou. V CzechIdM je s kažou stránkou či formulářem svázáno workflow,
které běží na pozadí a obstarává přechody mezi stránkami a akce na datech, například třídění údajů
záznamů v tabulkách. Pomocí GenericManagedBean je možné získat k těmto workflow přístup
přímo z šablony stránky.
4.3.1. Metoda getPageParameters
Navrací parametry stránky. Ty mohou sloužit jako zdroj dat pro přidružené workflow.
4.3.2. Metoda processSubmit
Pomocí této metody je možné posunout přidružené workflow do dalšího stavu. V parametru metody
uvádíme název přechodu k dalšímu stavu.
4.3.3. Metoda processAction
Různé varianty této metody slouží k provedení akce v podobě workfow. Název akce je mapován
na název workfow. Tato metoda tedy spustí workflow daného názvu a nastaví mu proměnné (podle
parametrů předaných této metodě). Pokud je akce spuštěna ze stránky, se kterou je asociované
nějaké workflow, bude toto workflow nastaveno jako rodič toho nově spouštěného. Po skončení nově
spuštěného workflow dojde tedy k přechodu do dalšího stavu rodičovského workflow. Což je často
smyčka zpět na uzel zobrazující stránku, ze kterého byla spuštěna akce.
25
Kapitola 4. Prezentační vrstva
4.3.4. Metoda processActionWithNewWorkflow
Funkce této metody je stejná jako u "processAction" s tím rozdílem, že nové workflow není spouštěno
jako podworkflow toho aktuálního.
4.4. JSF šablony
CzechIdM používá JSF a framework Richfaces, ze kterého používá některé komponenty, například
<rich:dataTable> či <rich:tree>.
Šablony se nachází v projektu BCV_IdM/WebContent a jsou děleny podle rozhraní na
administrátorské a uživatelské.
Výhodou těchto šablon je, že pokud některou část používáme na více místech (například menu je
použito na každé stránce), můžeme ji definovat na jednom místě a v ostatních šablonách ji jednoduše
vkládat. Nedochází tak ke zbytečné duplikaci kódu, a pokud menu měníme, stačí ho změnit na
jediném místě a změna se promítne do všech stránek.
<ui:define name="submenu">
<ui:include src="submenu.xhtml" />
</ui:define>
Příklad 4.1. Do šablony se vkládá jiná šablona submenu.xhtml.
Protože má téměř každý formulář v CzechIdM vlastní šablonu, je vhodné vkládání využít.
4.5. Psaní formulářů pomocí JSF a workflow
V CzechIdM jsou přechody mezi jednotlivými JSF šablonami řízeny pomocí workflow, která běží
v pozadí. Potřebujeme tedy způsob, jak z šablony ovlivnit běh workflow na pozadí a jak mu
předat informace. K tomu slouží třída GenericManagedBean, jíž je věnován samostatný oddíl
dokumentace.
4.5.1. Spuštění nového workflow
Spuštění nového workflow provedeme ze šablony zavoláním jedné z metod třídy
GenericManagedBean. V ní uvedeme, jaké workflow má spustit a jaké případné parametry mu má
předat.
Třída GenericManagedBean se nachází v BCV_IdM/src/eu.bcvsolutions.idm.ui.
<s:button action="#{genericBean.processAction}"
value="#{messages.admin_users_action_new_organisation}"
styleClass="menu_button"
rendered="#{s:hasPermission('ORGANISATION', 'CREATE')}">
<f:param name="action" value="organisation.new" />
</s:button>
Příklad 4.2. Jak spustit nové workflow.
26
Propojení JSF šablon a workflow
Kód v příkladu zobrazí tlačítko pro vytvoření nové organizace. Po kliknutí na tlačítko se spustí metoda
processAction, která spustí nové workflow definované pomocí elementu <f:param> s atributem
name="action" a value="organisation.new", který udává, které workflow má být spuštěno.
Za povšimnutí stojí atribut rendered, který udává, za jaké podmínky se má tlačítko zobrazit. Zde se
zobrazí, pokud má aktuálně přihlášený uživatel právo na vytváření organizací.
Workflow, které chceme spustit musí být pojmenované a tímto názvem ho poté spouštíme.
<process-definition xmlns="urn:jbpm.org:jpdl-3.2" name="organisation.new">
... stavy ve workflow
</process-definition>
Příklad 4.3. Každé workflow musí být pojmenované.
V ukázce je vidět jak se v elementu <process-definition> pomocí atributu name workflow
pojmenuje. Vytváření workflow je v této dokumentaci věnována samostatná kapitola.
4.5.2. Propojení JSF šablon a workflow
Často potřebujeme přenášet data z workflow do šablony. Uděláme například ve workflow dotaz na
databázi a vybereme všechny uživatele, které potom chceme v šabloně zobrazit v tabulce. K tomu,
abychom to mohli udělat, potřebujeme data uložit v kontextu workflow. Důvod je ten, že právě kontext
workflow je přístupný ve stránce jim zobrazené.
Data uložíme do kontextu namapováním proměnné s daty na název, pod kterým bude hodnota
proměnné přístupná v kontextu. Dělá se tak pomocí elementu <variable>. Takto namapovaná
proměnná se poté přenese do šablony.
Element <variable> obsahuje atribut name, což je jeho název, na který se odkazujeme v šabloně.
Dále obsahuje atributy mapped-name a access. Atribut mapped-name slouží k tomu k mapování
jmen proměnných mezi skriptem ve workflow a šablonou. Pokud jsou názvy stejné, nemusí se
mapped-name používat. V atributu access můžeme nastavit, zda chceme do proměnné z našeho
zdrojového kódu ukládat. V takovém případě nastavíme hodnotu write a proměnná je poté dostupná
v parametrech stránky, a můžeme ji tedy v šabloně vypisovat. Chceme-li ji pouze načítat, tedy
například nějakou hodnotu z formuláře chceme poslat do workflow, aby ji náš kód ve workflow mohl
dál zpracovávat, tak použijeme hodnotu read. Možná je i kombinace read,write a to ve chvíli, kdy
chceme proměnnou například načíst ze šablony a poté nějakým způsobem změnit její hodnotu ve
workflow. Hodnota read funguje jako filtr. Pokud nevytvoříme žádnou proměnnou <variable>, která
má přístup read, máme v uzlu všechny proměnné dostupné ke čtení. Nesprávné nastavení atributu
access bývá častým zdrojem chyb.
<node name="retrieveData">
<description>
Získá userView uživatele.
</description>
<event type="node-enter">
<script>
<expression>
import eu.bcvsolutions.idm.data.Data;
27
Kapitola 4. Prezentační vrstva
import eu.bcvsolutions.idm.app.Application;
import eu.bcvsolutions.idm.data.view.View;
import eu.bcvsolutions.idm.data.util.Enums;
View userView = Data.checkoutView(View.Type.USER, userName);
</expression>
<variable name="userName" access="read" mapped-name="userName" />
<variable name="userView" access="write" mapped-name="userView" />
</script>
</event>
<transition to="deleteIdentity"></transition>
</node>
Příklad 4.4. Pomocí elementu <variable> můžeme ukládat data, která budeme zobrazovat v
šabloně a nebo data z šablony číst.
V ukázkovém zdrojovém kódu vidíme, kdy načítáme ze šablony proměnnou userName, což je
uživatelské jméno uživatele. Tato proměnná je uložená ve <variable> s přístupem read. Poté
pomocí této proměnné získáme View userView uživatele, které si uložíme do workflow proměnné
userView, abychom userView mohli používat v šabloně a nebo v dalších uzlech workflow.
Nyní již máme data uložena v kontextu workflow a můžeme tedy zobrazit stránku, která bude tythel
data prezentovat uživateli. Zobrazení stránky má na starosti třída ShowPageAction. Ta očekává,
že ji určíme, kterou stránku má zobrazit. Na výběr jsou dvě možnosti. První je, specifikovat stránku
přímo konstantou (v příkladě níže) pomocí elementu "pageName". Druhá možnost je, že řekneme,
pod jakým názvem v kontextu workflow je cesta ke stránce. K tomu slouží element "pageNameVar".
Stránka je zobrazována při události "node-enter" - tedy při vstupu do uzlu. Uzel je typu "state".
To znamená, že běh workflow nebude pokračovat, dokud mu někdo neřekne, že tak má udělat.
Typicky to bude právě uživatel kliknutím na najaké tlačítko na stránce. Tímto tlačítkem se bude volat
metoda "processSubmit" s názvem přechodu, který se má použít. V tomto případě by to mohl být
"processSubmit('close')" nebo "processSubmit('reset')".
<state name="showPage">
<event type="node-enter">
<action class="eu.bcvsolutions.idm.app.workflow.ShowPageAction">
<pageName>admin/user/view</pageName>
</action>
</event>
<transition name="close" to="end-state1" />
<transition name="reset" to="checkoutView" />
</state>
Příklad 4.5. Zobrazení stránky z workflow
4.5.3. Zobrazení dat workflow v JSF stránce
Jak zobrazit uložená data z workflow? Data musí být uložena v elementech <variable> a poté je
můžeme v JSF šabloně získat z parametrů stránky.
To uděláme v šabloně pomocí hodnoty #{pageParameters.variables}. V nich jsou přístupné
všechny uložené proměnné. Je vhodné si v JSF šabloně #{pageParameters.variables} uložit
do proměnné, a zkrátit tím zápis.
28
Ovlivnění již běžícího workflow
<c:set var="vars" value="#{pageParameters.variables}"/>
<h:outputText value="#{vars.userView['firstName']} #{vars.userView['lastName']},
#{vars.userView['email']}" />
Příklad 4.6. Je vhodné si page parametry uložit do proměnné, lépe se s nimi pak pracuje.
4.5.4. Ovlivnění již běžícího workflow
Předpokládejme, že máme již běžící workflow a chceme ho posunout do dalšího stavu, například pro
zobrazení jiné stránky. To provedeme zavoláním metody na třídě GenericManagedBean.
<h:commandButton action="#{genericBean.processSubmit('save')}"
value="#{messages.cmn_btn_save}" />
Příklad 4.7. Změna stavu workflow.
Po kliknutí na tlačítko dojde ke spuštění přechodu <transition> s názvem save, který se postará o
uložení. Zde je vidět, proč je důležité přechody ve workflow pojmenovávat.
4.5.5. Internacionalizace
K tomu, abychom toho docílili internaciontalizace, je zapotřebí, aby nebyl text v
šablonách psán přímo, ale přes objekt messages. Toho dosáhneme použitím
#{messages.nazev_textoveho_retezce}. Textové řetězce jsou vypsány v BCV_IdM/src/
eu.bcvsolutions.idm.ui.msgcat.{admin|common|user}, zde jsou soubory .properties. Na
texty v nich uvedené odkazujeme pomocí jejich názvu v šabloně.
Pro každý jazyk existuje v CzechIdM zvláštní .properties soubor. Nové jazykové mutace lze snadno
docílit přeložením příslušného .properties souboru.
<h:commandButton action="#{genericBean.processSubmit('save')}"
value="#{messages.cmn_btn_save}" />
<h:commandButton action="#{genericBean.processSubmit('reset')}"
value="#{messages.admin_cmn_reset_view}"
immediate="true" />
<h:commandButton action="#{genericBean.processSubmit('close')}"
value="#{messages.cmn_btn_close}"
immediate="true" />
Příklad 4.8. TODO: sem dát nadpis
29
Kapitola 4. Prezentační vrstva
Obrázek 4.1. Ukázka .properties souboru.
Soubor lze prohlédnout v Eclipse v módu Source (zdrojový kód) nebo Properties, kdy pomocí tlačítka
Add můžeme přidávat další řetězce. Samozřejmě je možné také řetězce editovat a mazat.
30
Workflow
5.1. Jak vytvořit workflow
5.1.1. Úvod
V této sekci se podíváme na workflow v CzechIdM, ukážeme si, kdy a k čemu se v CzechIdM
workflow používají a na příkladu se naučíme, jak vytvořit vlastní workflow.
Každé jednotlivé workflow definuje nějaký proces v CzechIdM. Může to být například zablokování
identity, odstranění identity, vytvoření nové role nebo přiřazení role uživateli. Podobně jsou pomocí
workflow implementovány vnitřní funkce CzechIdM: když v záložce "Uživatelé" kliknete na sloupec,
podle kterého má být tabulka setříděna, postará se o třídění workflow spuštěné na pozadí formuláře.
V CzechIdM používáme technologii JBPM, což je engine napsaný v jazyce Java, který obstarává
průběh workflow, časování, ukládání a načítání nedokončených procesů z databáze. V technologii
JPBM je workflow definováno pomocí schématu, které se skládá z uzlů a přechodů mezi uzly.
V jednom okamžiku se spuštěné workflow nachází v jednom uzlu. Po spuštění je to vždy pevně
stanovený počáteční uzel. Každý uzel může obsahovat Java instrukce, které se provedou při vstupu
do uzlu. Na základě jejich průběhu a výsledku je uzel opuštěn po některém přechodu do jiného
uzlu. Pokud je uzel koncovým uzlem, z něhož nevychází žádné přechody, workflow skončí. Schéma
jednoduchého workflow, které vypisuje všechny existující role v CzechIdM, si můžeme prohlédnout na
následujícím obrázku:
31
Kapitola 5. Workflow
Nahoře na obrázku vidíme počáteční uzel "start-state1". V něm se workflow ocitne vždy po svém
spuštění. Po vykonání instrukcí v uzlu "start-state1" se workflow přesune jediným přechodem do uzlu
"reset", z něj do uzlu "search" (všimněte si, že přechody jsou orientované) a do uzlu "showPage", v
němž je uživateli zobrazena stránka. Z tohoto uzlu vedou přechody dva: na základě chování uživatele
workflow rozhodne, zda se vydá po přechodu k uzlu "reset", nebo po přechodu ke koncovému uzlu
"end-state1", ve kterém je workflow ukončeno.
Naše nové workflow vytvoříme v jazyce jPDl, pomocí kterého zachytíme schéma našeho workflow v
běžném xml formátu. Řekněme, že chceme vytvořit workflow, pomocí kterého deaktivujeme zadaného
uživatele. Chceme, aby se naše workflow jmenovalo "disableUser", ve " BCV_IdM-ejb/repoObjects/
{identifikaceProjektu}/workflows" tedy vytvořme složku s názvem "disableUser" a v ní vytvořme soubor
"processdefinition.xml". Uvnitř tohoto souboru zadefinujeme naše workflow.
5.1.2. Ukázkové workflow
Otevřeme si soubor "processdefinition.xml" a nahoru napišme hlavičku xml souboru a úvodní tag,
kterým specifikujeme, že se jedná o definici workflow:
32
Ukázkové workflow
<?xml version="1.0" encoding="UTF-8"?>
<process-definition xmlns="urn:jbpm.org:jpdl-3.2"
name="disableUser">
</process-definition>
Atribut "name" je důležitý, musí workflow jednoznačně pojmenovat, neboť právě přes něj bude
workflow z CzechIdM vyhledáno a spuštěno. Dovnitř do tagu <processdefinition> budeme
definovat jednotlivé uzly našeho workflow.
Uzlů rozlišujeme několik typů, každému typu přísluší jeden xml tag. V naprosté většině případů
vystačíme s následujícími typy: počáteční uzel (tag <start-state>), koncový uzel(tag <endstate>), stav (<state>) a běžný uzel (<node>). Stav se od běžného uzlu liší v jedné podstatné
věci: po vstupu do běžného uzlu workflow pokračuje prvním přechodem pryč, zatímco ve stavu
se workflow zastaví a čeká na signál z vnějšku, že může pokračovat. V našem souboru tedy
vytvořme počáteční stav, koncový stav a tři běžné uzly. Přechody mezi uzly vytvoříme pomocí tagu
<transition>
<start-state name="start-state">
<transition to="getUserView"/>
</start-state>
<node name="getUserView">
<transition to="setUserDisabled"/>
</node>
<node name="setUserDisabled">
<transition to="checkinView"/>
</node>
<node name="checkinView">
<transition to="end-state"/>
</node>
<end-state name="end-state"/>
Workflow, které jsme takto zadefinovali (a které zatím nic nedělá, protože uzly neobsahují žádné
instrukce), zachycuje následující schéma:
33
Kapitola 5. Workflow
Nyní se postupně zaměříme na jednotlivé uzly a doplníme do nich příslušné Java instrukce.
Předpokládejme, že naše workflow dostane na vstupu parametr "userName", ve kterém bude jméno
uživatele, který má být zablokován. V uzlu "getUserView" bychom chtěli ověřit, zda je tento parametr
korektně zadán, a načíst pohled na daného uživatele:
<node name="getUserView">
<event type="node-enter">
<script>
<expression>
import eu.bcvsolutions.idm.data.util.StringUtils;
import eu.bcvsolutions.idm.app.Application;
import eu.bcvsolutions.idm.data.Data;
import eu.bcvsolutions.idm.data.view.View;
if (StringUtils.isEmpty(userName)) {
throw new IllegalArgumentException("Parametr 'userName' nemůže být null nebo prázdný");
}
View userView = Data.checkoutView(View.Type.USER, userName);
</expression>
34
Ukázkové workflow
<variable name="userName" access="read" />
<variable name="userView" access="write"/>
</script>
</event>
<transition to="setUserDisabled"/>
</node>
Java instrukce jsme do uzlu vložili obalené tagy <event>, <script> a <expression>. Za
povšimnutí stoji tagy <variable> po ukončení tagu <expression>. V nich je zapotřebí vyjmenovat
všechny proměnné, jejichž doba života přesahuje uzel, tedy pokud existují již z uzlu předchozího
(nebo jsou některým z parametrů workflow), nebo se budou ještě používat v dalších uzlech a jejich
změny se mají promítnout do vnějšího světa. K tomu slouží tag <variable>; v atributu "name" se
uvádí název proměnné, v atributu "access" potom typ přístupu: "read" pouze pro čtení, "write" pro
zápis, "read, write" pro čtení i zápis. Důležitou součástí jsou importy, jejich opomenutí bývá častým
zdrojem chyb. Na tomto místě je dobré si uvědomit, že zdroj píšeme v prostředí xml, znak "menšítka"
tedy musíme psát jako <, podobně znak "většítka" jako > a logickou konjunkci jako &&
V ukázce si také můžeme prohlédnout jednoduchý způsob, jak získat informace o konkrétní entitě
(tedy například uživateli, roli, organizaci...) v CzechIdM. Ve workflow pracujeme s takzvanými pohledy
(view) na konkrétní entitu. View můžeme snadno získat statickou metodou checkoutView na třídě
Data. Prvním parametrem je typ view, druhým identifikátor entity, v našem případě jméno uživatele.
Po zavolání checkoutView je na view daného uživatele vystaven zámek, nesmíme proto zapomenout
před ukončením našeho workflow view zase odemknout! K tomu se dostaneme ve třetím uzlu.
V prvním uzlu jsme načetli data o uživateli, nyní chceme provést samotnou deaktivaci:
<node name="setUserDisabled">
<event type="node-enter">
<script>
<expression>
import eu.bcvsolutions.idm.app.Application;
import eu.bcvsolutions.idm.data.view.View;
import eu.bcvsolutions.idm.data.user.UserViewHandler;
userView.put(UserViewHandler.DISABLED_ATTRIBUTE,true);
Application.logInfo("Uzivatel " + userName + " byl deaktivovan.",new Object[0]);
</expression>
<variable name="userView" access="read,write"/>
<variable name="userName" access="read"/>
</script>
</event>
<transition to="checkinView"/>
</node>
V tomto uzlu jsme provedli změnu pohledu (přesná struktura UserView a dalších je k nahlédnutí v
kapitole o datové vrstvě) a celou akci zalogovali. K logování slouží statické metody log{typ logu}
na třídě Application. Logování je vhodné zejména pro účely ladění. Zbývá uložit view, aby se
změny propagovali k entitě. To provedeme ve třetím uzlu:
<node name="checkinView">
<script>
35
Kapitola 5. Workflow
<expression>
import eu.bcvsolutions.idm.data.view.View;
import eu.bcvsolutions.idm.data.Data;
Data.checkinView(userView);
</expression>
<variable name="userView" access="read,write"/>
</script>
<transition to="end-state"/>
</node>
Statickou metodou checkinView na třídě Data jsme propagovali změny v pohledu k samotné entitě,
tedy k deaktivovanému uživateli. Tím jsme také uvolnili zámek. Kdybychom chtěli uvolnit zámek, ale
změny z nějakého důvodu nepropagovat, použijeme metodu releaseViewLock(View userView).
Naše jednoduché workflow je hotovo!
Uvnitř workflow můžeme spustit pravidlo (viz sekce "Pravidla") pomocí metody executeRule na třídě
Application. Metoda bere jako první parametr název pravidla, jako druhý parametr mapu vstupních
parametrů pro pravidlo. Uvnitř workflow je také možné spouštět jiná workflow jako podprocesy, k tomu
slouží metoda startWorkflow na třídě Application. Také tato metoda bere jako první parametr
název workflow, jako druhý mapu parametrů. Obdobou metody startWorkflow je pro asynchronní
spuštění workflow (nečeká se, až workflow skončí) metoda startWorkflowAsynchronously.
5.2. Notifikace pomocí e-mailu
Součástí workflow často bývá e-mailová notifikace uživatelů, kterých se proces týká.
Je-li například uživatel deaktivován, je vhodné mu zaslat e-mail. K tomu slouží metoda
sendEmailToIdentity(String identityName, String templateName, Map<String,
Object>) na třídě Application. Jejím prvním parametrem je jméno uživatele, kterému má být email zaslán. Druhým je název šablony, která má být použita, třetím její parametry. CzechIdM zasílá emaily postavené na základě šablon. Každá šablona je samostatný xml dokument, uložený v adresáři
" BCV_IdM-ejb/repoObjects/{identifikaceProjektu}/emailTemplates". S parametry lze uvnitř šablony
pracovat pomocí notace #{nazev_parametru}.
<?xml version="1.0" encoding="UTF-8"?>
<emailTemplate xmlns="urn:jbpm.org:bcv_emailTemplate-1.0" name="UserRoleApprove">
<language>cs</language>
<subject>Schválení přidání role uživateli #{userFullName}</subject>
<text>
Dobrý den,
žádáme Vás o schválení přidělení role "#{roleName}" uživateli "#{userName}".
Popis role: #{roleDescription}
</text>
</emailTemplate>
5.3. Workflow engine
Jako workflow engine je použito jBPM.
36
Předdefinované proměnné
Definice procesů jsou uloženy v db v tabulce workflow_definitions. Zde vyskytujici se definice ale ještě
nejsou viditelné samotnému jBPM. Aby mohl být proces spustěn, tak musí být deployovan v tabulkách
s prefixem JBPM. K tomu slouží metoda WorkflowControler.cleanCache. Ta provede deploy (a
tím pádem aktualizaci) všech definic a vymazaní vyrovnavací paměti. Tabulka workflow_definitions je
pozůstatek z dřívějška, kdy byla všechna workflow mezi wait stavy držena pouze v paměti. Výjimkou
bylo čekání v task uzlu, kdy se stav procesu ukládal do db. Poté ale docházel k chybám. Když se v
rámci zpracování tasku spustilo další wf, které mělo být pouze v paměti, tak ve skutečnosti běželo v
JbpmContextu a přistupovalo k db. Tam ovšem nebyly požadovaná data. Do budoucna se počítá se
zrušením tabulky workflow_definitions. Definice by se pak deployvaly přímo do tabulek JBPM. Bude je
ale třeba rozšířít tak, aby tam bylo možné udržovat:
• runAs - pod právy jakého uživatele má být wf spouštěno
• resultTTL - jak dlouho se má uchovávat výsledek běhu workflow (uchovávání výsledků zatím není
implementováno)
• sourceCode - zdrojové xmlko
• atributy pro audit a zamykání
Běžící workfow je v paměti reprezentováno instancí třídy WorkflowInstance. Ta přidává do
kontextu jBPM procesu konstanty a další pomocné proměnné a zajišťuje, aby se proces spouštěl
pod správnými právy (runAs). Pokud bylo workflow spuštěno jako podworkflow (v konstruktoru je
specifikovane rodičovské wf), tak je odpovídajícímu JBPM procesu nastaveno superProcessToken
na rootToken procesu rodičovského workflow. Také udržuje proměnné a název aktuálního uzlu, aby
nebylo potřeba přistupovat k db při každém požadavku na čtení. Stav procesu je načítán z databáze
před každým volaním metody signal pro změnu stavu. Změněný stav je opět uložen do databáze po
té, co proces dorazí do čekacího stavu nebo skončí. Vše se děje v rámci metody sendSignal.
Další důležitou třídou je ShowPageAction, která implementuje ActionHandler. V procesech
se tedy používá jako akce pro zobrazení požadované stránky. Akce je vykonávána tak, že nejdříve
jsou vytvořeny PageParameters. Do těch je uložen odkaz na aktuální workflow a také jsou
zkopírovány proměnné z kontextu procesu. Pokud nemá dojít pouze k obnovení kontextu, tak je
zobrazena požadovaná stránka. Že má dojít pouze k uložení kontext procesu do PageParameters
se specifikuje nastavením parametru onlySaveContext na hodnotu "true".
5.3.1. Předdefinované proměnné
Tyto proměnné jsou definované přímo ve zdrojácích JBPM.
Konkrétně: org.jbpm.graph.action.Script.createInputMap() a
org.jbpm.jpdl.el.impl.JbpmVariableResolver.resolveVariable().
Pokud ale uvedeme tyto proměnné v elementu variable, tak tím zrušíme jejich výchozí chování a
najdeme v nich pravděpodobně hodnotu null. Tyto proměnné jsou naopak přístupné i v případě, že
uvedeme výčet jiných promměných v elementech variable s přístupem pro čtení.
Název proměnné
Typ
executionContext
org.jbpm.graph.exe.ExecutionContext
token
org.jbpm.graph.exe.Token
node
org.jbpm.graph.def.Node
task
org.jbpm.taskmgmt.def.Task
37
Kapitola 5. Workflow
Název proměnné
Typ
taskInstance
org.jbpm.taskmgmt.exe.TaskInstance
Tabulka 5.1. Proměnné přístupné ve skriptu
Název proměnné
Typ
taskInstance
org.jbpm.taskmgmt.exe.TaskInstance
processInstance
org.jbpm.graph.exe.ProcessInstance
processDefinition
org.jbpm.graph.def.ProcessDefinition
token
org.jbpm.graph.exe.Token
taskMgmtInstance
org.jbpm.taskmgmt.exe.TaskMgmtInstance
contextInstance
org.jbpm.context.exe.ContextInstance
Tabulka 5.2. Proměnné přístupné v EL
5.4. Metody související s workflow na třídě Application
Workflow je možné spustit také z kódu. Toho docílíme puštěním statických metod na třídě Application.
Jde o statické metody public static Object startWorkflow(String name, Map<String,
Object> variables), public static Object startWorkflow2(String name,
Object... variables), public static void startWorkflowAsynchronously(String
name, Map<String, Objectgt; variables), public static void
startWorkflowAsynchronously2(String name, Object... variables) Ty spustí
workflow dle zadaného jména a předá mu na vstup zadané parametry. Spustíme-li workflow z kódu
metodou startWorkflow, potom se vykonávání našeho kódu přeruší, dokud pouštěné workflow
nedoběhne. Další možností je takzvané asynchronní spouštění. V takovém případě se workflow z
našeho kódu pustí a již se nečeká na výsledek.
Další metoda, která souvisí s workflow na tříde Application je metoda public static boolean
isWorkflowExists(String name). Ta pouze zjišťuje, zda workflow zadaného jména existuje.
5.5. Výstupní hodnota
Občas je potřeba, aby workflow vracelo nějakou výstupní hodnotu. Jak to uvnitř workflow zařídit? Mezi
variables přidáme tag
<variable name="stateResult" access="write" />
a hodnotu, kterou chceme mít na výstupu vložíme do proměnné stateResult. Toto se používá
například u webové služby.
38
Pravidla
6.1. Pravidla
Pravidla (rules) zastupují ve světě beanshellu (tedy Javě podobného skriptovacího jazyka, ve kterém
vytváříme naše workflow) procedury a funkce. Ukládáme do nich časté bloky instrukcí, které bychom
zbytečně znovu a znovu rozepisovali na různých místech v našem workflow.
Podobně jako workflow, definujeme i pravidla v xml souborech. Pravidla umístěna v adresáři podle
použití v adresáři "BCV_IdM-ejb/repoObjects/czechidem/rules" jsou uložena obecná pravidla bez
návaznosti ke konkrétnmu projektu. Všechna pravidla, která jsou specifická pro jedno dané nasazení
CzechIdM, jsou pak uložena v adresáři "BCV_IdM-ejb/repoObjects/projspec/rules".
6.2. Ukázkové pravidlo
V této sekci si ukážeme, jak napsat své vlastní jednoduché pravidlo. Řekněme, že chceme vytvořit
pravidlo, které na základě jména uživatele vrátí jméno jeho přímého nadřízeného ve struktuře
CzechIdM, pojmenujeme ho "getManager".
V adresáři "BCV_IdM-ejb/repoObjects/czechidm/rules" vytvořme soubor getManager.xml. V
něm zadefinujeme naše nové pravidlo. Nejprve vložíme obvyklou xml hlavičku a základní tag, který
specifikuje, že se jedná o definici pravidla:
<?xml version="1.0" encoding="UTF-8"?>
<rule-definition xmlns="urn:jbpm.org:bcv_rule-1.0" name="getManager">
</rule-definition>
Atribute "name" je důležitý, musí pravidlo jednoznačně identifikovat, přes toto jméno bude definice
pravidla vyhledána. Dovnitř do tagu <rule-definition> vepíšeme samotný kód pravidla.
Předpokládáme, že v parametru userName dostaneme jméno uživatele, jehož nadřízený má být
vrácen.
<?xml version="1.0" encoding="UTF-8"?>
<rule-definition xmlns="urn:jbpm.org:bcv_rule-1.0" name="getManager">
import eu.bcvsolutions.idm.data.Data;
import eu.bcvsolutions.idm.data.view.View;
import eu.bcvsolutions.idm.data.user.UserViewHandler;
View userView = Data.checkoutView(View.Type.USER, userName);
String manager = userView.get(UserViewHandler.IDMMANAGER_ATTRIBUTE);
Data.releaseViewLock(userView);
return manager;
</rule-definition>
Na začátku pravidla nesmíme zapomenout uvést všechny importy, jejich opomenutí bývá častým
zdrojem chyb. Uvnitř pravidla můžeme spustit další pravidlo pomocí metody executeRule na třídě
39
Kapitola 6. Pravidla
Application. Metoda bere jako první parametr název pravidla, jako druhý parametr mapu vstupních
parametrů pro pravidlo. Pravidlo může spustit i sebe samo; rekurze není problém. Uvnitř pravidla
je také možné spouštět workflow, k tomu slouží metoda startWorkflow na třídě Application.
Také tato metoda bere jako první parametr název workflow, jako druhý mapu parametrů. Obdobou
metody startWorkflow je pro asynchronní spuštění workflow (nečeká se, až workflow skončí)
metoda startWorkflowAsynchronously. V příkladu pravidla výše si povšimněme metody
checkoutView na třídě Data. S její pomocí snadno získáme pohled na informace o konkrétní entitě
(například uživateli, roli, organizaci...). Jejím prvním parametrem je typ entity, druhým její identifikátor.
V okamžiku, kdy je pohled vytvořen, je identita uzamčena pro ostatní uživatele. Na konci pravidla tedy
musíme zámek uvolnit metodou releaseViewLock.
Navíc je potřeba dávat si pozor na drobnou chybu obsaženou v beanshellu, která se týká deklarace
proměnných. V případě že v průběhu pravidla používáme cyklus (for, while) a v uvnitř tohoto cyklu
zadeklarujeme nějakou svou lokální proměnnou, pak často dochází v beanshellu k chybě která nám
znemožní tuto proměnnou upravovat (při čtení její hodnoty dostaneme vždy hodnotu s jakou byla
proměnná deklarována, bez ohledu co do ní zapíšeme). Ochranou proti této chybě je deklarování
proměnné před cyklem. Proměnno pak můžeme v ámci cyklu upravovat, na jeho začátku do ní třeba
vložit požadovanou počáteční hodnotu.
6.3. Rule engine
Pravidla jsou xml soubory (uložené v db) s jedním elementem, jehož obsahem je skript v BeanShellu.
V databázi jsou uloženy v tabulce rules_definitions.
Vykonáváni pravidel má na starosti třída RuleControler, přesněji její metoda executeRule. Ta
načte zdrojový kód požadovaného pravidla. Dále do contextu pravidla doplní kostanty z pravidla
getBusinessConstants a přidá proměnné předané metodě jako parametr. Nakonec spustí interpretr
BeanShellu a vrátí výsledek vykon
6.4. Transformační pravidla
Pro dané schéma na koncovém systému může administrátor nastavit pravidlo, kterým se bude
hodnota atributu v CzechIdM transformovat na hodnotu atributu na koncovém systému. Podobně
může nastavit pravidlo, kterým se bude hodnota na koncovém systému transformovat na hodnotu
v CzechIdM. Obě pravidla mají stejné vstupní parametry a obě musí navracet transformovanou
hodnotu.
Název parametru
Typ parametru
Popis
Constants.
TRANSFORM_RULE_
ATTR_RESOURCE
String
Název koncového systému
Constants.
TRANSFORM_RULE_
ATTR_NAME
String
Název atributu v CzechIdM
Constants.
TRANSFORM_RULE_
ATTR_VALUE
Object
Hodnota atributu, která má být
transformována
Tabulka 6.1. Parametry, které má k dispozici transformační pravidlo
40
Pravidla pro výpočet nové hodnoty atributu
6.5. Pravidla pro výpočet nové hodnoty atributu
Během aktualizace atributů schématu, které vychází z některé přiřazené role, je zapotřebí stanovit
novou hodnotu atributu. Existuje několik možností, jednou z nich je výpočet nové hodnoty na základě
staré hodnoty pomocí pravidla, které vytvoří sám administrátor. Pravidlo musí vracet novou hodnotu
atributu.
Název parametru
Typ parametru
Popis
UserView.
RULE_VARIABLE_
VIEW_ATTRIBUTE
UserView
Pohled na uživatele, s jehož
účtem je pracováno
UserView.
RULE_VARIABLE_
ATTR_NAME
String
Název atributu
UserView.
RULE_VARIABLE_
ACCOUNT_ATTRS
DTO
Atributy účtu, který je
aktualizován
UserView.
RULE_VARIABLE_
ATTR_OLD_VALUE
Object
Předchozí hodnota atributu
Tabulka 6.2. Parametry, které má k dispozici pravidlo pro výpočet nové hodnoty atributu
6.6. Korelační pravidla
Během rekonciliace je zapotřebí párovat účty. K tomu slouží korelační pravidla, která může
administrátor stanovit v administrátorském rozhraní. Pravidlo musí vracet jméno identity, s níž se má
účet spárovat.
Název parametru
Typ parametru
Popis
Generic
Synchronization.
WFC_SYNC_TYPE
Generic
Synchronization.
SyncType
Typ obecné
synchronizace, tedy
SyncType.SYNCHRONIZATION
nebo
SyncType.RECONCILIATION
Generic
Synchronization.
WFC_ACCOUNT_UID
String
Jedinečný identifikátor účtu
Generic
Synchronization.
WFC_RESOURCE_NAME
String
Název systému, na němž se
nachází účet
Generic
Synchronization.
WFC_RESOURCE_
ATTRIBUTES
DTO
Atributy schématu, na němž se
účet nachází
Generic
Synchronization.
WFC_SCHEMA_NAME
String
Název schématu, na němž se
nachází účet
Tabulka 6.3. Parametry, které má k dispozici korelační pravidlo
41
Kapitola 6. Pravidla
6.7. Pravidla pro blokování účtů
V administrátorském rozhraní je možné u jednotlivých schémat stanovit, jakým způsobem mají být
případně blokovány účty. Administrátor má na výběr ze tří možností, jedna z nich je "BY_RULE".
Blokování účtů pravidlem je nejobecnější varianta, která přenechává veškerou zodpovědnost na
administrátorovi. CzechIdM neočekává žádnou návratovou hodnotu.
Název parametru
Typ parametru
Popis
operationType
OperationType
Pro blokování je tato
hodnota konstantně vždy
OperationType.DISABLE
resourceName
String
Název systému, na němž se
nachází účet
schemaName
String
Název schématu, na němž se
nachází účet
schemaAttributes
DTO
Atributy schématu, na němž je
účet mazán
accountUid
String
Jedinečný identifikátor účtu,
který má být zablokován
identityName
String
Jméno identity, která je
vlastníkem účtu
Tabulka 6.4. Parametry, které má k dispozici pravidlo pro blokování účtů
6.8. Pravidla before provisioning a after provisioning
Administrátor může ve svém rozhraní nastavit pravidla, která se mají spustit před začátkem
provisioning účtů a po jeho skončení. Zvolení konkrétního pravidla může snadno provést přes
"Systémy" - zvolení konkrétního systému - "Pokračovat" - "Editovat" u konkrétního schématu. Pravidly
before a after provisioning může administrátor specifikovat libovolné akce, které mají být provedeny
před nebo po skončení provisioning. Může dokonce provisioning konkrétního účtu zcela zablokovat,
pokud pravidlo before provisioning vrátí hodnotu null.
Název parametru
Typ parametru
Popis
operationType
OperationType
Udává typ operace, tedy
OperationType. DISABLE
(případně také ADD,
APPROVE, CHANGE, DENY,
DISABLE,. ENABLE,
REMOVE, RENAME, SET,
UNLINK, WANT_ADD)
resourceName
String
Název systému, na němž se
nachází účet, u něhož bude
prováděno provisioning
schemaName
String
Název schématu, na němž se
nachází účet, u něhož bude
prováděno provisioning
42
Pravidla before provisioning a after provisioning
Název parametru
Typ parametru
Popis
schemaAttributes
DTO
Atributy schématu, na němž
se nachází účet, u něhož bude
prováděno provisioning
accountUid
String
Jedinečný identifikátor účtu,
u něhož bude prováděno
provisioning
identityName
String
Jméno identity, která je
vlastníkem účtu, u něhož bude
prováděno provisioning.
Tabulka 6.5. Parametry, které mají k dispozici pravidla before a after provisioning
43
44
Logování
7.1. Úvod do logování v CzechIdM
Veškeré informace se prvotně zaznamenávají do příslušných tabulek v repository. Chybový výstup
může být také směrován přes syslog do libovolného jiného úložiště. Například do jiné databáze nebo
do souboru. Ale i v takovém případě dojde nejdříve k zápisu do repository idm a až po té k předání
informací syslogu. V repository tedy budou vždy všechny informace. Je to především pro potřeby
reportů. Ty jsou vytvářeny vždy z dat vedených v repository.
7.2. Co všechno je logováno?
V identity manageru se zaznamenává několik druhů informací, které při provozu vznikají. Ty jsou
zapisovány do různých tabulek. Následující tabulka shrnuje o které informace se jedná a kam jsou v
rámci repository zapisovány.
Typ záznamu
Tabulka
Chyba, warování, ladící informace, ...
log
Emaily (odeslané i neodeslané kvůli chybě)
email_log
Auditní informace
tabulky s prefixem
"audit_log"
Uživatelské požadavky
user_requests
Tabulka 7.1. Logované informace a kde jsou uloženy
Detailně jsou jednotlivé typy záznamů popsány v dalším textu.
7.3. Auditní informace
Auditními informacemi se myslí takové, které mohou někdy později sloužit k přezkoumávání událostí,
co se v identity manageru staly. Například informace o tom, kdo, co a kdy změnil, vytvořil, odstraníl
a podobně. Záznamy tohoto typu jsou umísťovány do více tabulek v repository, které mají prefix
"audit_log". Například informace o všem, co se stalo s nějakou identitou nebo jejím účtem, je ukládáno
do "audit_log_for_identity".
7.4. Uživatelské požadavky
Uživatelské požadavky jsou veškeré "akce", k nimž dá pokyn uživatel skrze nějaké rozhrání identity
manageru. Například se může jednat o požadavek na zobrazení seznamu všech uživatelů, který
uživatel vyšle kliknutím na patřičný odkaz. Kromě toho, o jaký požadavek se jedná, jsou také
zaznamenány informace o uživateli samotném.
Atribut
Popis
id
Jednoznačný identifikátor. Jak je generován, je uvedeno níže v textu.
turnNumber
Číslo, které udává, kolikátý je tohle požadavek daného uživatele v rámci sezení
(od přihlášení).
userName
Uživatelské jméno přihlášeného uživatele.
45
Kapitola 7. Logování
Atribut
Popis
begin
Datum a čas, kdy byl požadavek vytvořen (podán).
duration
Počet milisekund udávající, jak dlouho trvalo zpracování požadavku.
ipAddress
IP adresa, ze které uživatel daný požadavek poslal.
interfaceType
Typ rozhraní, ze kterého požadavek pochází. Možnosti jsou: WEB, WS,
TEST_NO_GUI
servletPath
Cesta k servletu.
queryString
Atributy zadávané v adresní řádce prohlížeče.
Tabulka 7.2. Sledované atributy uživatelského požadavku
7.5. Identifikátor požadavku
Identifikátor je generován ihned při vytvoření požadavku. Mezi touto akcí a uložením požadavku do
databáze je vykonáno velké množství operací. Některé z těchto operací jsou okamžitě zalogovány.
Aby se vědělo, na základě jakého požadavku byly operace vykonávány, je ke každému takovému
záznamu přidáván právě identifikátor aktuálně zpracovávaného požadavku. To je takového, který byl
vytvořen, ale ještě nebyl uložen.
Ve skutečnosti požadavek nemusí být zapsán úplně pokaždé do databáze. Pokud totiž v rámci
jeho zpracovávání není do repository zapsán žádný záznam, který by se na něho odkazoval,
není uložen ani tento požadavek. Pokud bude potřeba, je tuto funkčnost možno změnit v
"LoggingUtils.endUserRequest".
Z výše uvedeného je zřejmé, že generování identifikátoru nebude moci mít na starosti databáze nýbrž
aplikace. Jako (s velkou pravděpodobností) jedinečný identifikátor se používá UUID (Universally
Unique Identifier) verze 4 rozšířený o identifikátor aktuálního vlákna a počet milisekund od 1.1.1970.
Takovéto identifikátory jsou používáné i na dalších místech aplikace a to vždy prostřednictvím třídy
"eu.bcvsolutions.idm.data.UuidBasedId".
7.6. Začátek a konec uživatelského požadavku
Pro označení začátku a konce (a provedení potřebných akcí) jsou ve třídě
"eu.bcvsolutions.idm.data.logging.LoggingUtils" určeny statické metody "beginUserRequest" a již
zmíněná "endUserRequest". To kdy jsou tyto metody volány ovšem záleží na rozhraní, ze kterého
požadavek pochází.
Nejčastěji používaným je webové rozhraní. To je vytvořeno pomocí JSF frameworku a tudíž může
být využito tzv. phase listener, který dokáže reagovat na jednotlivé fáze zpracovávání požadavku. K
tomuto účelu slouží třída "eu.bcvsolutions.idm.app.page.PagePhaseObserver" a speciálně její metoda
"beforePhaseAction". Její deklarace je:
@Observer("org.jboss.seam.beforePhase")
public String beforePhaseAction()
V těle metody se zjistí, ve které fázi se nacházíme. Pokud půjde o fázi "RESTORE_VIEW", tak
zavoláme "LoggingUtils.beginUserRequest". Naopak ve fázi "RENDER_RESPONSE" budeme volat
metodu "endUserRequest".
46
Zápis logu
7.7. Zápis logu
IdmLogger decorator je implementací Log rozhraní. Primárně se snaží zapisovat do databáze
(prostřednictvím DBLoggeru). Zkrácené informace také zapíše do logu, který dekoruje. V případě
neúspěšného zápisu jde do takového logu kompletní informace.
Zápis do DB logu běží v samostatné transakci. Důvod je ten, že pokud už jednou záznam pošlu
do syslogu, nejde tento také rollbackovat. Lepší by ale asi bylo, kdyby se error logy zapisovaly v
samostatné transakci, kdežto auditní logy v transakci stejné v jaké beží logovaná operace. Tento rys
může být předmětem dalšího vývoje.
7.8. Jak logovat z kódu
Kromě logování, které je prováděno přímo z kódu CzechIdM, může být výhodné logovat
některé informace ze spouštěných workflow, neboť i ta mohou prostřednictvím třídy Data
manipulovat s datovou vrstvou. Druhým důvodem pro logování z workflow může být
vypisování stavů workflow pro účely ladění během vývoje. K logování je možné použít statické
metody Application.logInfo, Application.logWarn, Application.logInfo,
Application.logError, Application.logDebug a Application.logFatal. Pro přístup k
auditnímu logu slouží na třídě Application metoda getIoLog.
Application.logInfo("Tento retezec bude zalogovan s dulezitosti {0}", new String[]
{"info"});
AuditOperationsLogger logger = Application.getIoLog();
//zalogovani do auditniho logu - uzivateli "admin" byl odebran atribut
logger.logIdentity(OperationTarget.ATTRIBUTE, OperationType.REMOVE, "admin");
47
48
Schvalování
8.1. Schvalovací proces
Schvalovací proces v CzechIdM je elektronická obdoba procesu běžného třeba na úřadech. Pokud
něco chcete, musíte o to požádat. Vaše žádost je poté doručena k vyřízení člověku, který má
schvalování na starosti. Ten rozhodne, zda vaší žádost schválí, nebo zamítne. V případě první
možnosti je vám následně předáno to, o co jste žádali. Na úřadech (a v mnohých firmách) jsou tyto
žádosti v papírové podobě, a tudíž se může snadno stát, že je doručena ke špatnému člověku nebo
úplně ztracena. Je-li schvalovací proces řešen emailovou komunikací, hrozí, že ji člověk v záplavě
jiných emailů ztratí. Navíc je i tato forma přenosu informací relativně nebezpečná (kdokoliv ji může
přečíst). Pokud k výše zmíněnému přičteme i to, že akce a rozhodnutí kolem žádostí nejsou nikde
zaznamenávány, je jasné, že tyto způsoby nejsou zdaleka ideální.
Lepší způsob nabízí CzechIdM. Výhody jsou především:
• Rychlost - vaše žádost je okamžitě doručena schvalovateli. Pokud ten na ni nebude reagovat po
definovanou dobu, je možné žádost přeposlat na někoho jiného.
• Bezpečnost - informace v žádosti vidí pouze schvalovatel. Emailem jde pouze informace o tom, že
žádost byla podána a odkaz na ni. Před jejím zobrazením je ovšem vyžadována autentizace.
• Dohledatelnost - podání žádosti, rozhodnutí schvalovatele i to, zda vám bylo "dáno" to, o co jste si
žádali, je zaznamenáváno. Je tedy například možné kdykoliv zjistit, kdo, kdy a jak rozhodl ohledně
schválení žádosti.
8.1.1. Pohled uživatele
Uživatelem je v tomto případě myšlen jak žadatel, tak schvalovatel. Žadatel si po přihlášení do
uživatelského rozhraní může například požádat o roli, která ho bude opravňovat k přístupu do
nějakého systému. Třeba do systému účetnictví. Jelikož tento systém obsahuje informace, které
nemůže vidět kdokoliv, podléhá vytvoření účtu v systému schválení hlavní účetní. Té tedy přijde email,
že má schválit přístup. Proto se přihlásí do CzechIdM a zobrazí si detail žádosti. Po té, co klikne na
tlačítko schválit, je žadateli okamžitě vytvořen účet.
8.1.2. Pohled administrátora
Administátor má na rozdíl od obyčejného uživatele přístup do administračního rozhraní. Díky tomu je
schopen provádět mnohem více operací. K těm, které se týkají schvalovacího procesu, patří:
• Vytvoření role, jejíž vlastnictví opravňuje ke schvalování.
• Přiřazení této admin role nějakému uživateli. Tím se z uživatele stává schvalovatel (který ale ještě
nemá nic na schvalování).
• Konfiguraci role tak, aby její přiřazení vyžadovalo schválení. U role se definují schvalovatelé. Od té
chvíle jim budou chodit ke schválení žádosti o konfigurovanou roli.
Nyní si tyto operace popíšeme podrobněji. V CzechIdM není žádná výchozí role, která by definovala
schvalovatele. Jeji vytvoření je ale velmi jednoduché. Na záložce "Role" klikneme na tlačítko "Nová
admin role". Vyplníme libovolné jméno a na záložce "Oprávnění" vybereme "ROLE" a zaškrtneme
"APPROVE". Dále přidáme oprávnění "USER_TASK","APPROVE" a "USER","APPROVE", potřebná
49
Kapitola 8. Schvalování
při schvalování. Roli můžeme samozřejmě přidat i další oprávnění, definovat její podrole nebo
systémy, na kterých přiřazuje účet. Kliknutím na tlačítko "Uložit" roli vytvoříme.
Nyní můžeme vytvořenou roli přiřadit uživateli, ze kterého chceme udělat schvalovatele. V menu na
záložce "Uživatelé" vyhledáme tohoto uživatele a klikneme na odkaz editovat. Zobrazí se editační
formulář. Přejdeme na záložku "Role a kontrolované organizace" a přidáme námi vytvořenou roli. Také
vybereme organizaci, pro kterou budou všechny admin role uživatele platit. Po klepnutí na tlačítko
"Uložit" dojde k vytvoření schvalovatele.
Zbývá u nějaké role určit schvalovatele. Opět tedy přejdeme na záložku "Role" a vybereme roli,
jejíž přiřazení komukoliv budeme chtít nejdříve potvrdit schvalovatelem. Uděláme tak na záložce
"Schvalovatelé" v detailu role. Pro vyhledání schvalovatele můžeme použít filtr. Pokud chcete zobrazit
všechny, tak nechte vyhledávací pole prázdná a klepněte na tlačítko "Vyhledat". Zobrazí se všichni
uživatelé, kteří mají roli s oprávněním schvalovat. Některé z nich vybereme a roli uložíme. Tím je
nastavení schvalovatele hotovo. Důležití je ještě to, že pokud definujeme více schvalovatelů u jedné
role, tak každému z nich dojde, při pokusu o přiřazení role, požadavek na schválení. Kdo první
schválí, ten vyhrává. Ostatním pak takovíto požadavek zmizí.
8.1.3. Pohled vývojáře
Schvalovací procesy jsou z části implementovány v Java kódu a z části pomocí workflow. Schvalovací
formuláře samozřejmě též využívají i JSF. V následujícím textu popíšeme, jak jsou jednotlivé části
provázány a jak spolu komunikují. I když se schvalování může týkat i jiných událostí, my si to, jak je
schvalování implementováno, ukážeme na příkladu schválení přiřazení role.
Celý proces začíná voláním "Data.checkinView" na "UserView", do jehož uzlu "roles" byla přidána
role vyžadující schválení. Takovéto view se dostane přes třídy "Data" a "UserManagementBean"
až do objektu třídy "UserViewHandler". Zde se zjistí, že byla přidána role a že má tato role
určené schvalovatele. K těmto operacím dochází v metodě "processViewRolesAttribute" a z ní
volané "startRoleApproveWfsIfNeeded". Druhá z uvedených metod pak také spouští workflow
"user.role.approve", které notifikuje schvalovatele a vytváří schvalovací požadavek.
Toto workflow tedy obsahuje uzel typu "task-node". V okamžiku, kdy se běh programu dostane do
tohoto uzlu, je vytvořen "task" (schvalovací požadavek, úkol) s následujícími proměnnými (žádná z
nich není povinná, ale doporučujeme vyplňovat alespoň "approvers", "approvalInfo", a "pageId" nebo
"workflowName"):
• approvers - seznam schvalovatelů
• roleName - název role, která se schvaluje
• userView - view uživatele, kterému má být role přidána.
• pageId - id stánky, která se má použít pro zobrazení tohoto úkolu. V případě schvalování rolí to je
"include/roleApprove".
• workflowName - název workflow, která bude mít na starosti zobrazení uživatelského požadavku.
Pokud je nastavena tato proměnná (a není null), tak zastíní i případně nastavenou proměnnou
"pageId". Použití nachází v případě složitějšího zpracovávání požadavku, kdy nevystačíme s
pouhým zobrazením stránky následovaným rozhodnutím o schválení.
• approvalInfo - informace o schvalování, které se použijí pro záznam do audit logu. K tomu
dochází po ukončení požadavku ve workflow "userTask.detail". Je možné doplnit položky
"targetIdentityName", "newValue", "oldValue", "operationSubject", "detail".
50
Pohled vývojáře
Proměnné jsou poté dostupné ve view daného tasku. Tím, že je vytvořen task, dojde k přerušení
workfow. Běh programu se vrací do java kódu, kde dochází k uložení stavu workflow do databáze.
Dále program pokračuje kódem v "UserViewHandleru", což může znamenat další spuštění workflow
pro jinou přidanou roli. Workflow zůstává přerušeno do doby ukončení schvalovacího požadavku
(schválení, nebo zamítnutí).
Schvalovateli byl ve workflow "user.role.approve" poslán email o tom, že na jeho schválení čeká
požadavek o přiřazení role. Přihlásí se do uživatelského rozhraní IdM a přejde na stránku s úkoly.
Tím se spouští workflow "ui.userTask.list", které vytáhne z repository všechny neukončené úkoly
přihlášeného uživatele. V administračním rozhraní je, pro získání všech úkolů, používáno workflow
"userTask.list". To zatím dělá téměř to stejné, co workflow z uživatelského rozhraní. Dá se ale
předpokládat, že časem bude jeho funkcionalita rozšířena tak, aby si administrátor s dostatečnými
právy mohl vylistovat úkoly i jiných uživatelů. Pak již se tato dvě workflow budou velmi lišit. Nyní
je rozdíl pouze ve formulářích, které zobrazují. Jedná se buď o "user/userTask/userTasks" pro
uživatelské rozhraní nebo "admin/userTask/userTasks" pro administrační rozhraní. Formuláře jsou
opět velmi podobné, ale i u nich to v budoucnu nebude platit.
Po kliknutí na název úkolu, je spuštěno workflow "userTask.detail". To
si nejdříve obstará kompletní view úkolu s daným id. Poté spustí akci
"eu.bcvsolutions.idm.app.workflow.ShowUserTaskPageAction", která z předaného pohledu zjistí,
kterou stránku má použít pro zobrazení úkolu. Zjišťuje to na základě proměnné "pageId". Pokud
není definována, je použita výchozí stránka "/adminOrUser/userTask/detail.xhtml", která nedělá nic
jiného, než že zobrazí všechny proměnné zobrazovaného úkolu v tablce. Pokud je proměnná "pageId"
definována, tak je naopak zobrazena stránka, jejiž id je hodnotou proměnné. Ve skutečnosti je ale
stránka nejdříve vložena do "/adminOrUser/userTask/customDetail.xhtml" a ta je pak zobrazena.
Workflow "userTask.detail" čeká během zobrazování stránky v uzlu "showPage". Z něho vedou
následující přechody, jimž mohou odpovídat tlačítka na formuláři:
• finishAndSave - ukončí úkol, aniž by došlo ke schválení nebo zamítnutí.
• save - uloží změny v úkolu. Úkol ale tímto není ukončen a stále bude zobrazován v seznamu
aktivních úkolů.
• reset - znovu načte view úkolu.
• close - neuloží změny v úkolu, ani ho neukončí.
• approve - nastaví proměnnou "___IS_TASK_APPROVED___" na hodnotu "true" a poté ukončí a
uloží úkol.
• deny - chová se stejně jako přechod "approve" s tím rozdílem, že nastaví hodnotu proměnné na
"false".
Proměnnou "___IS_TASK_APPROVED___" kontroluje UserTaskManagementBean, který je volán
z workflow prostřednictvím "Data.checkinView". Pokud je nastavena, tak podle její hodnoty použije
přechod "approved", nebo "denied" z "task-node". Jedná se o uzel ve workflow, které je asociované s
právě ukončeným taskem. Tím se běh programu dostává zpět do workflow, které úkol vytvořilo a bylo
tedy až do tohoto okamžiku pozastaveno.
Pokud je místo "pageId" použito "workflowName", tak v uzlu "userTask.detail" dojde ke spuštění v
proměnné uvedeného workflow. Tomu je do kontextu přidána proměnna "taskView" s pohledem na
aktuálně zpracovávaný požadavek. Očekává se, že workflow před ukončením nastaví proměnnou
"stateResult". Její hodnotou by mělo být taskView. Pokud bude v TaskView atribut nextAction, tak se
51
Kapitola 8. Schvalování
jeho hodnota použije pro navigaci do dalšího uzlu workflow "userTask.detail". Hodnota tedy odpovída
názvu přechodu, které jsou uvedeny výše v seznamu.
8.1.4. Příklad vytvoření schvalovací úlohy ve workflow
Následující kód vytvoří schvalovací požadavek a pozastaví workflow, ve kterém se nachází. Jakmile
dojde ke schválení, nebo zamítnutí, běh workflow bude pokračovat buď přechodem do uzlu "addRole",
nebo do uzlu "logDisapproval".
<task-node name="createUserTask">
<task name="SchvaleniPridaniRole">
<assignment pooled-actors="#{approvers}"></assignment>
<controller>
<variable name="approvers" access="read"/>
<variable name="roleName" access="read" />
<variable name="userName" access="read" />
</controller>
<description></description>
</task>
<transition name="approved" to="addRole"/>
<transition name="denied" to="logDisapproval"/>
</task-node>
8.2. Delegace schvalovacích procesů
Delegace schvalovacích procesů rozšiřuje možnosti schvalovacích procesů popsaných v předchozí
kapitole. Tato funkcionalita dává uživatelům možnost dynamicky si volit zástupce na které budou
delegovány příchozí žádosti o schválení. Příkladem může být šéf delegující své žádosti na sekretářku
(která by v běžné situaci neměla příslušné pravomoce), nebo dočasná delegace mezi kolegy v době
dovolené.
8.2.1. Pohled uživatele
Možnosti delegací jsou přístupné pouze uživatelům s určitými právy. To proto že uživatel si vybírá své
delegáty ze seznamu ostatních uživatelů, a musí mít proto právo si příslušný seznam prohlédnout.
V případě že tato práva nemá nezobrazí se mu ani možnost přejít ve webovém rozhraní na formulář
delegací. V opačném případě, rozhodne-li se delegace využít, má delegátor možnost specifikovat,
na koho chce své žádosti delegovat, a určit od kdy do kdy bude delegace aktivní (v případě že
časový interval nespecifikuje je delegace uvažována na neurčito). Po potvrzení své volby je následně
všem potenciálním delegátům vytvořena žádost o schválení delegací. Po jejím potvrzení se stává
delegace aktivní a všechny žádosti přicházející na delegátora jsou poslány jeho delegátům. Delegát
pak má právo potvrdit schválit nebo odmítnout žádost stejně jako původní schvalovatel (delegátor).
V případě že žádost má definováno více schvalovatelů probíhá schvalování stejně jako v případě
nedelegovaných žádostí,s tím rozdílem že delegátor je v seznamu schvalovatelů naahrazen
seznamem všech svých aktivních delegátů. Žádost pak zmizí poté co jí vyřídí jeden ze schvalovatelů.
8.2.2. Pohled vývojáře
Formulář webového rozhraní je ovládán pomocí workflow "userTask.delegation". V případě že
si uživatel přidá nového delegáta je spuštěno workflow "userTask.delegation.approve". To pošle
52
Pohled vývojáře
potenciálnímu delegátovi žádost o schválení delegací. V okamžiku kdy je žádost schválena je přidán
do extendet atributu delegates původního žadatele.
Samotné delegace jsou pak aplikovány pomocí jednoduchého pravidla "getDelegates". Vstupem
tohoto pravidla je LinkedList schvalovatelů (ve stejné podobě v jaké je používán při tvorbě
schvalovacího tasku) výstupem je nový list schvalovatelů ve kterém jsou všichni uživatelé s aktivními
delegáty nahrazeni seznamem těchto delegátů (a to rekurzivně, tj. delegáti jsou také testováni na
přítomnost vlastních delegátů). Pokud by v systému byla vytvořena delegační smyčka (A deleguje na
B, B na C a C zpět na A) bude výsledným příjemcem žádosti její původní adresát.
53
54
Plánování úloh
9.1. Scheduler a task executer
Workflow a další procesy (neboli úlohy) je možné spouštět asynchronně. K tomu slouží třída
TaskControlerBean, která zařadí úlohu do fronty Message Driven Beany TaskExecutorBean.
Ta už pak (v jiném vlákně) provádí samotné vykonávání úlohy. Počet současně vykonávaných úloh je
závislí na velikosti poolu pro tuto beanu. To se dá nastavit v konfiguraci aplikačního serveru.
Úlohy jsou reprezentovány třídami, které implementují rozhraní ApplicationTask. Jsou to například
RunWorkflowTask, SynchronisationTask nebo TimerTask. Každá z těchto implementací
specifikuje, jak konkretně se má úloha vykonat.
Pro příklad uvedeme, jak spustit workflow asynchronně. Jako při většině jiných operací
použíjeme jednu z fasád. Pro tento účel je určena třída Application a její statická metoda
startWorkflowAsynchronously.
Úlohy je možné naplánovat na spustění v konkrétní čas a také nastavit periodu jejich spouštění. Toto
se dělá nastavením odpovídajících atributu v SchedulerTaskView a následně jejich uložením
prostřednictvím Data.checkinView. Během metody checkinView dojde i k nastavení systémového
časovače. Třída SchedulerTaskManagementBean odpovídající za uložení pohledu totiž po jeho
uložení volá Scheduler.updateTimerServiceAccordingToTaskAndSetTimerHandle. Tato
metoda zařídí vytvoření případně zrušení časovače. Do volitelných informacích časovače uloží id
naplánované úlohy a naopak do atributu úlohy uloží timer handle. Vzniká tak obousměrná vazba mezi
úlohou a časovačem.
55
56
Koncové systémy
10.1. Definice koncového systému
10.1.1. Pravidla spouštěná před a po operaci na systému
U každého schématu lze definovat pravidlo, které se má spustit před nebo po provedení každé
operace na systému. Z pravidla je samozřejmě možné spustit nějaké workflow, které například vytvoří
schvalovací úlohu.
Pravidlu jsou předány následující argumenty:
Název
Popis
operationType
O jakou operaci se jedná. Jde o výčtový typ
OperationType a možnými hodnotami jsou zatím:
ADD, CHANGE, REMOVE, RENAME
resourceName
Název koncového systému.
schemaName
Název schématu.
schemaAttributes
Atributy, které se budou posílat (měnit, nastavovat) nebo
které byly poslány do koncového systému.
accountUid
Identifikátor účtu
identityName
Jméno IdM uživatele, kterému patří učet, na němž se
operace provádí.
Tabulka 10.1. Argumenty předávané pravidlům
Pravidlo, spouštěné před operací musí vrátit atributy, které se pošlou koncovému systému. Pokud
tedy nechce udělat žádnou změnu, tak pouze vrátí ty samé atributy, co dostane v parametru
"schemaAttributes". Pokud je vráceno null, tak je operace přerušena.
10.1.2. Nastavení způsobu blokování (a odblokování) účtu
Jsou podporovýny dva způsoby blokace účtů. První je změnou hesla na neznámou hodnotu (splňující
politiku hesel na systému). Druhou je pak volání pravidla, které nastaví patřičný atribut.
Změna hesla je universální - funguje na všech systémech. Nevýhodou ale je, že uživatel musí mít i
zablokovaný přístup do IdM. V opačném případě by si totiž heslo mohl změnit. . Vzhledem k tomu, že
si IdM neukládá žádná hesla, není možné po odblokování účtu nastavit původní heslo. Uživatel si tak
musí heslo změnit z uživatelského rozhraní IdM.
Pokud je vybrán druhý způsob blokace účtů, tak IdM pouze zavolá pravidlo, které musí samo nastavit
atributy na správné hodnoty tak, aby došlo k blokaci nebo aktivaci účtu.
10.2. Přilinkování uživatelského účtu
„Ruční“ přilinkování uživatelského účtu probíhá tak, že IdM nejprve vyhledá všechny účty na
koncovém systému. Uživatel poté vybere účet, který chce přiřadit některé z identit v IdM. IdM vyzve
uživatele k výběru identity, které chce účet přiřadit. Tato identita musí mít přiřazenou roli, která ji
57
Kapitola 10. Koncové systémy
opravňuje k tomu mít účet na daném koncovém systému. Pokud identita tuto roli nemá, vyzve IdM
uživatele k tomu, aby některou roli identitě přiřadil.
Je možné přilinkovat pouze takový účet na koncovém systému, který má v tabulce účtů (v přehledu,
který se zobrazí) vyplněné schéma. Jeden uživatel může mít na koncovém systému pouze jeden účet
pro dané schéma.
Zobrazení přehledu uživatelských účtů na koncovém systému zajišťuje workflow
„resource.accounts.view“. Filtrování podle schemat je zajištěno přímo v průběhu komunikace s
koncovým systémem. Filtrování podle začátku jména a podle stavu účtu se provádí přímo v tomto
workflow. Tzn., že jsou nejprve načteny všechny účty (případně je proveden filtr na schéma) a poté se
ve workflow vyfiltrují účty, které nesplňují vyhledávací podmínky.
Přilinkování uživatelského účtu zajišťuje workflow „resource.accounts.link“. Workflow požádá uživatele
o vybrání identity a poté zašle požadavek na přilinkování. V případě, že při této akci dojde k chybě,
která je způsobená tím, že uživatel nemá přiřazenou potřebnou roli, načte workflow role, které toto
oprávnění poskytují a požádá uživatele o vybrání role. Při opětovném pokusu o přilinkování dojde k
tzv. checkoutView, nastavení nové role, přidání účtu do seznamu účtů a k tzv. checkinView.
Potřebná oprávnění:
• RESOURCE (READ, LINK_ACCOUNT)
• USER (READ, EDIT, EDIT_ACCOUNT)
• ROLE (READ)
10.3. Vypnutí reálných modifikací systému
V konfiguraci CzechIdM je možné nastavit, aby se změny na systémech ve skutečnosti neprováděly a
namísto toho byly změny pouze zapisovány do souboru. Toho lze docílit nastavením níže uvedených
parametrů v konfiguračním souboru (viz kapitolu Konfigurace).
• create_real_account_allowed=true
• update_real_account_allowed=true
• fake_resources_dir=META-INF/fakeResources/
10.4. Aktualizace hodnot atributů účtů na koncových
systémech
Při každém zpracování pohledu na identitu nebo roli v metodě checkinView na třídě Data jsou
aktualizovány hodnoty atributů na účtech. V zásadě je možné rozdělit aktualizování hodnot atributů
na účtech do dvou kategorií: aktualizaci z hlediska role a aktualizaci z hlediska identity. K aktualizaci
z hlediska role dochází při přidělení nové role, odebrání role nebo pozměnění role. Aktualizace z
hlediska identity je spouštěna při zpracování pohledu na identitu a může upravit atributy účtu, které
jsou přímo mapovány na některý atribut identity. Aktualizace z hlediska rolí je naproti tomu spouštěna,
pokud došlo k nějaké změně v přidělení rolí, tedy přiřazení nové role, odebrání role.
Propagaci hodnot atributů z CzechIdM na koncový systém zajišťuje třída
UserViewAttributesPropagator a její metody actualizeAccountsFromRoles a
actualizeAccountsFromIdentity.
58
Aktualizace z hlediska identity
10.4.1. Aktualizace z hlediska identity
Tento druh aktualizace je zajišťován metodou actualizeAccountsFromIdentity na třídě
UserViewAttributesPropagator. K aktualizaci dochází z workflow "user.before.checkin", které je
spouštěno z metody beforeSaveView při každém zpracování pohledu metodou checkinView na
třídě Data. Všechny mapované atributy jsou podle pohledu přepsány novou hodnotou.
10.4.2. Aktualizace z hlediska rolí
Tento druh aktualizace je zajišťován metodou actualizeAccountsFromRoles na třídě
UserViewAttributesPropagator. K aktualizaci dochází z metody processViewChanges na třídě
UserViewHandler.
Role přiřazená uživateli může znamenat vytvoření účtu na některém z koncových systémů. Některé
atributy na systému jsou poté propagovány na koncový systém právě na základě přiřazené role.
Může se ovšem stát, že se k jednomu koncovému systému vztahuje více rolí, které mají některé
atributy společné. V takovém případě musí CzechIdM řešit konflikt: jedna role může doplňovat atribut
například konstantou A, zatímco druhá konstantou B nebo pravidlem C. Která hodnota se má v
takovém případě použít? V této sekci je popsáno, jak je tento problém v CzechIdM řešen.
U každé identity v CzechIdM je veden seznam přiřazených rolí a jsou sledovány jeho změny. V
okamžiku, kdy dojde ke změně v seznamu, postupuje se podle následujícího algoritmu:
1. Pro všechny nově odebrané role:
• Označ všechny její atributy jako modifikované a vynuluj je.
2. Označ všechny účty na schématech, k nimž se nevztahuje žádná ze stávajících rolí, jako "ke
smazání".
3. Pro všechny role, které zůstaly přiřazeny:
• Pokud je role mezi nově přiřazenými, nastav příznak isNewAssigned na true.
• Pro všechna schémata dané role odstraň příznak ke smazání a projdi všechny atributy daného
schématu:
• Pokud atribut nemá být propagovaný, pokračuj dalším atributem.
• Pokud má být atribut propagován z identity a takový na identitě existuje, aktualizuj ho z
identity.
• Pokud má být atribut propagován z role:
• Pokud atribut na základě zvolené přepisovací strategie nemá být přepsán, pokračuj dalším
atributem. Rozhodnutí proběhne na základě zvolené přepisovací strategie takto:
• Strategie WRITE_IF_NOT_EXISTS: atribut bude zapsán, pokud pro daný účet atribut
zatím vůbec neexistuje.
• Strategie OVERWRITE_IF_MODIFIED: atribut bude přepsán, pokud je označen jako
modifikovaný, tedy například v případě, kdy byla odebrána jiná role pracující s tímto
atributem
• Strategie OVERWRITE_FIRST_TIME: atribut bude přepsán, pokud je role nově přiřazena
59
Kapitola 10. Koncové systémy
• Strategie OVERWRITE_ALWAYS: atribut bude přepsán
• Nyní je na základě role a staré hodnoty atributu vypočítána nová hodnota pro daný atribut.
Jsou dvě možnosti, jak může být tato nová hodnota vypočítána:
a. Pravidlem (pokud bylo nějaké příslušné nalezeno) ... nová hodnota je vypočítána na
základě parametrů, které jsou pravidlu zadány:
• parametr userView ... odkaz na view identity, pro niž je výpočet prováděn. Typu
UserView
• parametr attributeName ... název atributu. Typu String
• parametr accountAttributes ... atributy účtu identity na tomto schématu. Typu
DTO
• parametr oldValue ... hodnota atributu před spuštěním výpočtu. Typu Object
Pravidlem lze stanovit novou hodnotu v závislosti na hodnotě původní. Například může
být nová hodnota se starou kombinována, anebo mohou být ošetřeny situace, kdy se
původní hodnota přepisovat nemá (například pokud stará hodnota není null).
b. Konstantou (pokud nebylo nalezeno žádné příslušné pravidlo) ... stará hodnota je vždy
přepsána stanovenou konstantou. Pokud má být nová hodnota kombinována s původní
hodnotou nebo na ní jakkoli záviset (například se má přepisovat pouze tehdy, pokud je
stará hodnota null), je třeba použít pravidlo, ve kterém bude kombinování řešeno.
• Stará hodnota atributu je přepsána novou hodnotou.
4. Schémata označená ke smazání jsou smazána.
Příklad: Představme si systém, jehož atributy jednak souvisí s rolí "mail" a jednak s rolí "unix". Každá z
těchto rolí používá na daném systému svou množinu atributů. Některé z atributů mohou být používány
pouze rolí "mail", některé pouze rolí "unix", některé oběma rolemi. Mějme uživatele, kterému není
přiřazena ani role "mail", ani role "unix". V okamžiku, kdy je mu přiřazena role "unix", jsou na základě
pravidel a konstant pro roli "unix" vypočítány příslušné atributy. V okamžiku, kde je přiřazena také
role "mail", prochází se opět všechny atributy ve schématu. Přepočítají se jak atributy související
s rolí "mail", tak atributy související s rolí "unix". Řekněme, že obě role používají atribut "a". Atribut
se přepočítává postupně na základě všech rolí, s nimiž souvisí. Nejprve se tedy hodnota atributu
"a" stanoví konstantou nebo pravidlem role "unix", poté konstantou nebo pravidlem role "mail". Máli výsledná hodnota být kombinací obou hodnot (nikoli jen tou, která odpovídá poslední zpracované
roli), musí to být ošetřeno v pravidle u obou rolí. V okamžiku, kdy je uživateli odebrána role "mail",
jsou všechny atributy, se kterými role "mail" pracuje, nastaveny na null a tím označeny jako
modifikované. Při dalším zpracování role "unix" jsou atributy související s rolí "unix" opět přepočítány,
a výsledná hodnota tedy správně odpovídá pouze roli "unix". Kdyby byla role "mail" poslední rolí pro
dané schéma, bylo by toto po zpracování všech rolí pro příslušnou identitu odstraněno.
10.4.3. Standardní řešení výpočtu hodnot typu "merge"
Častým technickým požadavkem při napojení koncového systému je výpočet hodnoty atributu jako
kombinace (slití, "merge") atributů jednotlivých rolí. Typicky se používá v situaci, kdy jsou role na
koncovém systému mapovány na role v CzechIdM. Přiřazené role jsou potom jedním atributem
koncového systému a tento atribut musí být odvozen ze všech přiřazených rolí v CzechIdM. V našem
60
Standardní řešení výpočtu hodnot typu "merge"
příkladu předpokládejme, že je počítaným atributem například atribut "permission" a je počítán z rolí
Role1, Role2, ... RoleN, přičemž každá z těchto rolí přispívá do výsledné hodnoty řetězcem "AtrX" (X
je číslo role). Výslednou hodnotou pro přiřazené role Role2, Role4 a Role85 by měl být řetězec
"Atr1;Atr4;Atr85". Jak takového výsledku docílit?
V současnosti nejlepším řešením je zavedení mapovací mezitabulky v business konstantě a jedné
výjimečné "přístupové" role. Tato role přiřazuje příslušný koncový systém a zadává na něm atribut
"permission" pravidlem "mergePermission" s přepisovací politikou OVERWRITE_ALWAYS. Ostatní
role tento atribut nezadávají. V pravidle "mergePermission" je z userView načten seznam všech
aktuálně přiřazených rolí. Pro každou přiřazenou roli je v mapovací mezitabulce nalezen řetězec,
kterým daná role přispívá do výsledku. Z řetězců je sestavena výsledná hodnota atributu.
Výhodou tohoto přístupu je skutečnost, že není nutné pro každou roli z rolí Role1 až RoleN
implementovat vlastní pravidlo. Případné obohacení seznamu rolí o další pak znamená jen přidat do
mapovací tabulky v business konstantách dvojici "NovaRole - NovyAtribut".
61
62
Identity Connectors
11.1. Definice konektoru
Identity Connectors (dále jen konektory) jsou aplikační komponenty, prostřednictvím kterých se
spravují uživatelské účty (a nejen ty) na koncových systémech. Tvoří k nim jakousi fasádu, tj.
poskytují jednotné rozhraní pro práci s nimi. Koncové systémy jsou v tomto případě všechny aplikace
a systémy, které používají vlastní správu uživatelů, např. systémy pro sledování požadavků, HR
systémy, mzdové systémy atd. Úkolem konektorů je poskytovat jednotné rozhranní pro připojení se k
daným koncovým systémům a propagovat změny na tyto systémy, popř. z těchto systémů.
11.2. Lokální a vzdálený connector server
Každý konektor, který má být použit, je deployován do takzvaného connector serveru, což je aplikace,
která konektory obsluhuje a zasílá jim data. CzechIdM zpravidla používá lokální connector server,
který je součástí CzechIdM a je spouštěn a zastavován spolu s aplikačním serverem. Connector
server však může být spouštěn i jako zcela samostatná aplikace odděleně od CzechIdM. Takový
connector server nazýváme remote connector server a to, zda má být koncový systém napojen přes
lokální nebo vzdálený connector server, je nutné stanovit už v okamžiku definice typu systému.
Výhodou použití remote connector serveru může být rozložení zátěže mezi více fyzických strojů nebo
Java VM. Některé systémy (například Active Directory) musí být napojeny přes remote connector
server, protože konektor, který se pro napojení používá, je napsán v .NET a standardní lokální Java
connector server s ním neumí pracovat.
Pro úspěšné připojení k remote connector serveru je potřeba zadat host, na kterém server běží, port a
heslo.
Spuštění Java remote connectoru:
java -cp "connector-framework.jar:connector-framework-internal.jar:groovy-all.jar"
org.identityconnectors.framework.server.Main -run -properties ConnectorServer.properties
To, zda se použije lokální, nebo vzdálený konektor server, je věcí typu resource. Klíčovou třídou, která
na základě ResourceType rozhodne, který konektor server použít, je třída ConnectorUtil, konkrétně její
metoda getAPIConfiguration.
11.3. Funcionalita konektorů
Operace pro navázání spojení
• validace konfiguračních údajů konektoru
• otestování spojení s koncovým systémem
• navázání spojení s koncovým systémem
• ukončení spojení s koncovým systémem
63
Kapitola 11. Identity Connectors
Provisioning operace
• vytvoření nového uživatelského účtu, popř. skupiny, role, organizace apod.
• editaci stávajícího uživatelského účtu
• vyhledání uživatelského účtu dle zadaného kritéria
• vyhledání všech účtů
• vyhledání timestampu poslední modifikace sledovaných záznamů
• vyhledání záznamů jenž byly modifikovány po zadaném timestampu
11.4. Spouštění externích skriptů na koncových systémech
Pomocí konektorů, které tuto možnost podporují (např.: Universal JDBC konektor), je možné volat
jednorázové skripty na koncových systémech. To se hodí zejména v situacích, kdy prováděná akce
nijak nesouvisí s účtem na koncovém systému. Typickou situací může být správa organizací nebo
jednorázové stažení seznamu revokovaných certifikátů.
Ke spuštění externí akce slouží na třídě Data metoda runScriptOnResource. Jako vstup dostane
název systému, jazyk skriptu, text skriptu a mapu parametrů, které mají být skriptu předány na vstupu.
Je důležité si uvědomit, že chování této metody závisí na implementaci konkrétního konektoru.
Například Universal JDBC konektor předpokládá, že je-li zadaný jazyk "bsh", je v textu skriptu přímo
celé tělo skriptu. Naproti tomu pro "bsh_path" očekává v textu skriptu pouze cestu k souboru se
skriptem.
11.5. Struktura tříd Universal JDBC konektoru
Na příkladě našeho Universal JDBC konektoru si popíšeme obecnou strukturu Java tříd u konektorů.
Základní model je založen na Identity Connector Frameworku a je tedy pro všechny konektory stejný.
JDBCConnector
• Hlavní třída konektoru,
• Zde jsou implementavány všechny provisioning metody (vytvoření účtu, úprava účtu, smazání účtu,
získání atributů, vypsání seznamu všech účtů, spuštění synchronizace, navrácení času poslední
provedené synchronizace).
JDBCConnection
• Zajisťuje komunikaci s koncovým systémem,
• Implementuje metody pro testování spojení, jeho navázání a následné ukončení.
JDBCConfiguration
• Intance této třídy obsahují konfigurační údaje konektoru.
• Implementuje metodu pro validaci konfiguračních údajů.
Výše popsané třídy tvoří jen nutné minimum všech konektorů. Většina z nich má mnohem více tříd, a i
stávající tři třídy mají větší rozsah. V další podkapitole se podíváme na jednotlivé třídy blíže.
64
Jak použít Universal JDBC Connector
11.6. Jak použít Universal JDBC Connector
Universal JDBC Connector umožňuje napojení libovolné relační databáze pomocí technologie JDBC.
Manipulaci s daty v tabulkách obstarávají BeanShell (BSH) skripty, které jsou volány z konektoru a
jednotlivým akcím jsou přiřazeny při založení systému v administrátorském rozhraní. Každý skript
dostává mezi parametry instanci objektu Connection, jehož prostřednictvím může provádět manipulaci
s daty. V této sekci se blíž podíváme na nastavení systému a na jednotlivé skripty, na data, která
dostávají skripty na vstupu a na jejich očekávaný výstup.
11.6.1. Konfigurace konektoru
Konektor je standardně uložen v balíku eu.bcvsolutions.connector.jdbc-XXX.jar.
Název parametru
Popis
Příklad hodnoty
Název systému
Výstižný název, pod kterým
se systém např. zobrazuje
uživatelům.
Evidence čtenářů
Pouze ke čtení
Zaškrtnutím této možnosti je
odškrtnuto
zajištěno, že na koncovém
systému nebude moci Identity
Manager nic vytvořit, změnit ani
smazat.
Authority level
Určuje prioritu systému.
Hodnota větší než 0 znamená,
že půjde o autoritativní
zdroj pro IdM; čím vyšší, tím
autoritativnější. Poznámka:
největší prioritu má IdM
repository.
0, nebo 1 pro autoritativní
zdroje
Password
Heslo uživatele, s nímž se IdM
přihlašuje k databázi.
******
JDBC Driver
Driver pro spojení s databází.
• oracle.jdbc.driver.OracleDriver
pro Oracle
• com.mysql.jdbc.Driver
pro MySQL
• org.firebirdsql.jdbc.FBDriver
pro Firebird
Database name
Název databáze.
readers_repository
URL template
Template pro vytvoření url
pro JDBC konektor - za
hodnoty %h, %p a %d se
dosadí host, port a název
databáze. Umožňuje definovat
další vstupní hodnoty, např.
kódování.
• jdbc:oracle:thin:@%h:
%p:%d pro Oracle
• jdbc:mysql://
%h:%p/%d?
useUnicode=true&characterEncoding
pro MySQL
• jdbc:firebirdsql:%h/
%p:%d pro Firebird
65
Kapitola 11. Identity Connectors
Název parametru
Popis
Příklad hodnoty
Port number
Port, na kterém databázový
server naslouchá.
• 1521 pro Oracle
• 3306 pro MySQL
• 3051 pro Firebird
Username
Login uživatele, s nímž se IdM
přihlašuje k databázi.
root
Hostname
Adresa databázového serveru
localhost
Tabulka 11.1. Parametry systému napojeného pomocí Universal JDBC Connector
Dále se pro každou akci vyplní název BSH skriptu, který ji zpracovává. Jeden BSH skript přitom může
obsluhovat i více akcí. Pokud na koncovém systému nechceme nastavovat synchronizaci, není nutné
vytvářet SYNC a GET_LAST_SYNC_TOKEN skripty. SCHEMA skript se momentálně uplatňuje pouze
při vytváření schématu pro nový systém, kdy předvyplní atributy schématu.
BSH skripty musí být uloženy na stejném serveru, na kterém je deployován konektor. V nastavení
parametrů systému je třeba uvést plnou cestu k nim (např. /opt/czechidm/readersScripts/
create.bsh).
11.6.2. Skript CREATE
Skript slouží k vytvoření objektu na koncovém systému. Na výstupu vrací identifikátor nově
vytvořeného objektu, zpravidla účtu. Činí tak prostřednictvím instance třídy Uid jménem "newUid".
11.6.3. Skript CREATE
Název parametru
Typ parametru
Popis
objClass
ObjectClass
Třída objektu, která je
skriptem spravována. Obvykle
ObjectClass.ACCOUNT
attributes
Set<Attribute>
Množina atributů, které mají
být propagovány na koncový
systém
options
OperationOptions
Možnosti operace
conn
Connection
Objekt reprezentující JDBC
připojení k databázi
uid
Uid
Současný identifikátor objektu
Tabulka 11.2. Parametry na vstupu skriptu CREATE
Skript slouží k vytvoření objektu na koncovém systému. Na výstupu vrací identifikátor nově
vytvořeného objektu, zpravidla účtu. Činí tak prostřednictvím instance třídy Uid jménem "newUid".
/*
Tento skript vytvoří účet na koncovém systému napojeném pomocí Universal JDBC konektoru.
Zde jde o jednoduchou tabulku "accounts" obsahující sloupce "id", "firstname", "lastname" a
"state".
66
Skript CREATE
Na vstupu dostane skript od konektoru množinu atributů, ve kterých musí být atributy "jmeno" a
"prijmeni".
Když se účet korektně vytvoří, tzn. do tabulky se přidá nový záznam, z hodnoty "Id" nového
záznamu se zkonstruuje Uid nového účtu.
To se dosadí do objektu s názvem "newUid", odkud ho bude umět konektor přečíst.
*/
import
import
import
import
import
import
import
java.sql.Connection;
java.sql.Driver;
java.sql.DriverManager;
java.sql.ResultSet;
java.sql.SQLException;
java.sql.Statement;
java.sql.PreparedStatement;
import java.util.*;
import org.identityconnectors.framework.common.objects.*;
final String DB_ACCOUNTS = "accounts";
final
final
final
final
String
String
String
String
COLUMN_ID = "id";
COLUMN_FIRST_NAME = "firstname";
COLUMN_LAST_NAME = "lastname";
COLUMN_STATE = "state";
final String STATE_ACTIVE = "active";
final String FIRST_NAME_ATTR = "jmeno";
final String LAST_NAME_ATTR = "prijmeni";
boolean loging = true;
// Only ACCOUNT is allowed.
if (!objClass.is(ObjectClass.ACCOUNT_NAME)) {
throw new IllegalArgumentException("Bad object type. Only ACCOUNT is supported.");
}
//===============================
Metody skriptu
==============================
Uid insertNewAccount(Connection connection, Set attributes) {
if (attributes == null) {
return;
}
Attribute attr = null;
Iterator it = attributes.iterator();
String firstName = null;
String lastName = null;
while (it.hasNext()) {
attr = (Attribute) it.next();
if (attr.getName().equals(FIRST_NAME_ATTR)) {
firstName = attr.getValue().get(0);
}
if (attr.getName().equals(LAST_NAME_ATTR)) {
lastName = attr.getValue().get(0);
}
}
67
Kapitola 11. Identity Connectors
if ( firstName == null || lastName == null ) {
throw new RuntimeException("First name and last name must be set.");
}
String insert = "INSERT INTO `"+DB_ACCOUNTS+"` (`"+COLUMN_FIRST_NAME+"`, `"+COLUMN_LAST_NAME
+"`, `"+COLUMN_STATE+"`) " +
"VALUES ( ?, ?, ?);";
PreparedStatement insertStm = null;
ResultSet rs = null;
int lastID = -1;
Uid newUid = null;
try {
connection.setAutoCommit(false);
// Vytvorime novy zaznam.
insertStm = connection.prepareStatement(insert, java.sql.ResultSet.TYPE_FORWARD_ONLY,
java.sql.ResultSet.CONCUR_UPDATABLE);
insertStm.setString(1, firstName);
insertStm.setString(2, lastName);
insertStm.setString(3, STATE_ACTIVE);
rs = insertStm.executeQuery();
if (rs.next()) {
lastID = rs.getInt(COLUMN_ID);
} else {
throw new RuntimeException("No ID returned.");
}
newUid = new Uid(String.valueOf(lastID));
connection.commit();
} catch (SQLException e) {
if (connection != null) {
try {
//Rollback
connection.rollback();
} catch (SQLException excep) {
throw new RuntimeException(excep.getMessage());
}
}
logErrors(e.getMessage(), loging);
throw new RuntimeException(e.getMessage());
} catch (Exception ex) {
logErrors(ex.getMessage(), loging);
throw new RuntimeException(ex.getMessage());
} finally {
if (insertStm != null) {
insertStm.close();
}
if (connection != null) {
connection.setAutoCommit(true);
}
}
return newUid;
}
// Pokud je atribut TRUE, tak vypisuje zpravu "error" primo do standardniho chyboveho vystupu.
68
Skript UPDATE
void logErrors(String error, boolean log) {
if (log) {
System.err.println(error);
}
}
//===============================
Konec - Metody skriptu
==============================
// Vytvoření nového účtu na koncovém systému a získání jeho Uid.
// Proměnné conn a attributes dodává konektor.
newUid = insertNewAccount(conn, attributes);
Příklad 11.1. Skript create.bsh
11.6.4. Skript UPDATE
Název parametru
Typ parametru
Popis
objClass
ObjectClass
Třída objektu, která je
skriptem spravována. Obvykle
ObjectClass.ACCOUNT
attributes
Set<Attribute>
Množina atributů, které mají
být propagovány na koncový
systém
options
OperationOptions
Možnosti operace
conn
Connection
Objekt reprezentující JDBC
připojení k databázi
uid
Uid
Současný identifikátor objektu
Tabulka 11.3. Parametry na vstupu skriptu UPDATE
Skript slouží k aktualizaci objektu na koncovém systému. Na výstupu vrací identifikátor objektu po
úpravě. Činí tak prostřednictvím instance třídy Uid jménem "newUid".
/*
Tento skript aktualizuje účet na koncovém systému napojeném pomocí Universal JDBC konektoru.
Zde jde o jednoduchou tabulku "accounts" obsahující sloupce "id", "firstname", "lastname" a
"state".
Na vstupu dostane skript od konektoru
- atribut uid typu Uid
- množinu atributů attributes, ve kterých jsou modifikované atributy "jmeno" a "prijmeni".
Uid účtu zůstává stejné, takže se pouze dosadí do objektu s názvem "newUid", odkud ho bude
umět konektor přečíst.
*/
import
import
import
import
import
import
import
java.sql.Connection;
java.sql.Driver;
java.sql.DriverManager;
java.sql.ResultSet;
java.sql.SQLException;
java.sql.Statement;
java.sql.PreparedStatement;
69
Kapitola 11. Identity Connectors
import java.util.*;
import org.identityconnectors.framework.common.objects.*;
final String DB_ACCOUNTS = "accounts";
final
final
final
final
String
String
String
String
COLUMN_ID = "id";
COLUMN_FIRST_NAME = "firstname";
COLUMN_LAST_NAME = "lastname";
COLUMN_STATE = "state";
final String FIRST_NAME_ATTR = "jmeno";
final String LAST_NAME_ATTR = "prijmeni";
boolean loging = true;
// Only ACCOUNT is allowed.
if (!objClass.is(ObjectClass.ACCOUNT_NAME)) {
throw new IllegalArgumentException("Bad object type. Only ACCOUNT is supported.");
}
//===============================
Metody skriptu
==============================
Uid updateAccount(Uid uid, Connection connection, Set attributes) {
if (uid == null) {
throw new RuntimeException("UID is not set.");
}
if (attributes == null) {
return;
}
Attribute attr = null;
Iterator it = attributes.iterator();
String firstName = null;
String lastName = null;
// Zjištění hodnot modifikovaných atributů
while (it.hasNext()) {
attr = (Attribute) it.next();
if (attr.getName().equals(FIRST_NAME_ATTR)) {
firstName = attr.getValue().get(0);
}
if (attr.getName().equals(LAST_NAME_ATTR)) {
lastName = attr.getValue().get(0);
}
}
String select = "SELECT `"+COLUMN_FIRST_NAME+"`, `"+COLUMN_LAST_NAME+"` FROM `"+DB_ACCOUNTS
+"` WHERE `"+COLUMN_ID+"` = ?;";
PreparedStatement prepStmt = null;
ResultSet rs = null;
int lastID = -1;
Uid newUid = null;
try {
connection.setAutoCommit(false);
// Hodnota Uid je obsažena ve sloupci "id", pomoci toho najdeme účet
prepStmt = connection.prepareStatement(select, java.sql.ResultSet.TYPE_FORWARD_ONLY,
70
Skript UPDATE
java.sql.ResultSet.CONCUR_UPDATABLE);
prepStmt.setInt(1, Integer.parseInt(uid.getUidValue()));
rs = prepStmt.executeQuery();
if (!rs.next()) {
throw new RuntimeException("Account for given UID wasn't found.");
}
if (firstName != null) {
rs.updateString(COLUMN_FIRST_NAME, firstName);
}
if (lastName != null) {
rs.updateString(COLUMN_LAST_NAME, lastName);
}
rs.updateRow();
//Navratova hodnota (uid se nemeni).
newUid = uid;
connection.commit();
} catch (SQLException e) {
if (connection != null) {
try {
//Rollback
connection.rollback();
} catch (SQLException excep) {
throw new RuntimeException(excep.getMessage());
}
}
logErrors(e.getMessage(), loging);
throw new RuntimeException(e.getMessage());
} catch (Exception ex) {
logErrors(ex.getMessage(), loging);
throw new RuntimeException(ex.getMessage());
} finally {
if (prepStmt != null) {
prepStmt.close();
}
if (connection != null) {
connection.setAutoCommit(true);
}
}
return newUid;
}
// Pokud je atribut TRUE, tak vypisuje zpravu "error" primo do standardniho chyboveho vystupu.
void logErrors(String error, boolean log) {
if (log) {
System.err.println(error);
}
}
//===============================
Konec - Metody skriptu
==============================
// Aktualizace účtu na koncovém systému a získání jeho Uid.
// Proměnné uid, conn a attributes dodává konektor.
71
Kapitola 11. Identity Connectors
newUid = updateAccount(uid, conn, attributes);
Příklad 11.2. Skript update.bsh
11.6.5. Skript DELETE
Název parametru
Typ parametru
Popis
objClass
ObjectClass
Třída objektu, která je
skriptem spravována. Obvykle
ObjectClass.ACCOUNT
options
OperationOptions
Možnosti operace
conn
Connection
Objekt reprezentující JDBC
připojení k databázi
uid
Uid
Současný identifikátor objektu
Tabulka 11.4. Parametry na vstupu skriptu DELETE
Skript slouží ke smazání objektu na koncovém systému. Na výstupu nic nevrací.
/*
Tento skript obsluhuje smazání účtu na koncovém systému napojeném pomocí Universal JDBC
konektoru.
Zde jde o jednoduchou tabulku "accounts" obsahující sloupce "id", "firstname", "lastname" a
"state".
Mazání účtu se provádí vložením hodnoty "deleted" do sloupce "state", žádný řádek se ve
skutečnosti neodstraňuje.
Na vstupu dostane skript od konektoru atribut uid typu Uid.
*/
import
import
import
import
import
import
import
java.sql.Connection;
java.sql.Driver;
java.sql.DriverManager;
java.sql.ResultSet;
java.sql.SQLException;
java.sql.Statement;
java.sql.PreparedStatement;
import java.util.*;
import org.identityconnectors.framework.common.objects.*;
final String DB_ACCOUNTS = "accounts";
final String COLUMN_ID = "id";
final String COLUMN_STATE = "state";
final String STATE_DELETED = "deleted";
boolean loging = true;
// Only ACCOUNT is allowed.
if (!objClass.is(ObjectClass.ACCOUNT_NAME)) {
throw new IllegalArgumentException("Bad object type. Only ACCOUNT is supported.");
}
72
Skript DELETE
//===============================
Metody skriptu
==============================
// Označí účet s daným uid ke smazání (bez ohledu na jeho aktuální stav).
void deleteAccount(Uid uid, Connection connection) {
if (uid == null) {
throw new RuntimeException("UID is not set.");
}
PreparedStatement deleteStm = null;
String statement = "UPDATE `"+DB_ACCOUNTS+"` SET `"+COLUMN_STATE+"` = ? WHERE `"+COLUMN_ID+"`
= ?;";
try {
connection.setAutoCommit(false);
deleteStm = connection.prepareStatement(statement);
deleteStm.setString(1, STATE_DELETED);
deleteStm.setInt(2, Integer.parseInt(uid.getUidValue()));
deleteStm.executeUpdate();
connection.commit();
} catch (Exception ex) {
if (connection != null) {
try {
//Rollback
connection.rollback();
} catch (SQLException excep) {
throw new RuntimeException(excep.getMessage());
}
}
logErrors(e.getMessage(), loging);
throw new RuntimeException(e.getMessage());
} catch (Exception ex) {
logErrors(ex.getMessage(), loging);
throw new RuntimeException(ex.getMessage());
} finally {
if (deleteStm != null) {
deleteStm.close();
}
if (connection != null) {
connection.setAutoCommit(true);
}
}
}
// Pokud je atribut TRUE, tak vypisuje zpravu "error" primo do standardniho chyboveho vystupu.
void logErrors(String error, boolean log) {
if (log) {
System.err.println(error);
}
}
//===============================
Konec - Metody skriptu
==============================
// Smazání účtu na koncovém systému.
// Proměnné uid, conn a attributes dodává konektor.
deleteAccount(uid, conn, attributes);
73
Kapitola 11. Identity Connectors
Příklad 11.3. Skript delete.bsh
11.6.6. Skript LISTALL
Název parametru
Typ parametru
Popis
objClass
ObjectClass
Třída objektu, která je
skriptem spravována. Obvykle
ObjectClass.ACCOUNT
options
OperationOptions
Možnosti operace
conn
Connection
Objekt reprezentující JDBC
připojení k databázi
Tabulka 11.5. Parametry na vstupu skriptu LISTALL
Skript na výstupu vrací seznam objektů na koncovém systému. Činí tak prostřednictvím instance třídy
List<ConnectorObject> jménem "listOfIDs".
/*
Tento skript vrací seznam účtů na koncovém systému napojeném pomocí Universal JDBC konektoru.
Zde jde o jednoduchou tabulku "accounts" obsahující sloupce "id", "firstname", "lastname" a
"state".
Existující účet je takový, který má ve sloupci "state" hodnotu "active".
Seznam účtů se dosadí do objektu s názvem "listOfIDs", odkud ho bude umět konektor přečíst.
*/
import
import
import
import
import
import
import
java.sql.Connection;
java.sql.Driver;
java.sql.DriverManager;
java.sql.ResultSet;
java.sql.SQLException;
java.sql.Statement;
java.sql.PreparedStatement;
import java.util.*;
import org.identityconnectors.framework.common.objects.*;
final String DB_ACCOUNTS = "accounts";
final
final
final
final
String
String
String
String
COLUMN_ID = "id";
COLUMN_FIRST_NAME = "firstname";
COLUMN_LAST_NAME = "lastname";
COLUMN_STATE = "state";
final String STATE_ACTIVE = "active";
final String FIRST_NAME_ATTR = "jmeno";
final String LAST_NAME_ATTR = "prijmeni";
boolean loging = true;
// Only ACCOUNT is allowed.
if (!objClass.is(ObjectClass.ACCOUNT_NAME)) {
throw new IllegalArgumentException("Bad object type. Only ACCOUNT is supported.");
74
Skript LISTALL
}
//===============================
Metody skriptu
==============================
// Vrátí ConnectorObject pro účet na koncovém systému s daným uid
ConnectorObject getUser(String uid, Connection connection) {
ConnectorObject connectorObject = null;
ConnectorObjectBuilder builder = null;
String statementAccount = "SELECT `"+COLUMN_ID+"`, `"+COLUMN_FIRST_NAME+"`,
`"+COLUMN_LAST_NAME+"` FROM `"+DB_ACCOUNTS+"` WHERE `"+COLUMN_ID+"` = ?;";
PreparedStatement existStmt = null;
ResultSet rs = null;
String firstName = null;
String lastName = null;
Collection attributesCol = null;
try {
// Nalezení objektu s daným UID
existStmt = connection.prepareStatement(statementAccount);
existStmt.setInt(1, Integer.parseInt(uid));
rs = existStmt.executeQuery();
if (!rs.next()) {
// Ucet neexistuje
return null;
}
builder = new ConnectorObjectBuilder();
attributesCol = new ArrayList();
// Získání hodnot atributů
firstName = rs.getString(COLUMN_FIRST_NAME);
lastName = rs.getString(COLUMN_LAST_NAME);
// Vytvoření objektů typu Attribute se získanými hodnotami a přidání do seznamu
attributesCol.add(AttributeBuilder.build(FIRST_NAME_ATTR, firstName));
attributesCol.add(AttributeBuilder.build(LAST_NAME_ATTR, lastName));
builder.addAttributes(attributesCol);
// Nastavíme třídu objektu UID, Name a vytvoříme objekt.
builder.setObjectClass(ObjectClass.ACCOUNT);
builder.setUid(uid);
builder.setName(uid);
connectorObject = builder.build();
} catch (Exception ex) {
logErrors(ex.getMessage(), loging);
throw new RuntimeException(ex.getMessage());
} finally {
if (existStmt != null) {
existStmt.close();
}
}
return connectorObject;
}
// Vrátí seznam všech aktivních účtů na koncovém systému
75
Kapitola 11. Identity Connectors
List listAllAccounts(Connection connection) {
List allObjects = new ArrayList();
ConnectorObject object = null;
ConnectorObjectBuilder builder = null;
String statementAccount = null;
PreparedStatement accountStmt = null;
ResultSet rs = null;
int id;
builder = new ConnectorObjectBuilder();
statementAccount = "SELECT `"+COLUMN_ID+"` FROM `"+DB_ACCOUNTS+"` WHERE `"+COLUMN_STATE+"`
= ?;";
accountStmt = connection.prepareStatement(statementAccount);
accountStmt.setString(1, STATE_ACTIVE);
rs = accountStmt.executeQuery();
while (rs.next()) {
id = rs.getInt(COLUMN_ID);
object = getUser(String.valueOf(id), connection);
allObjects.add(object);
}
return allObjects;
}
// Pokud je atribut TRUE, tak vypisuje zpravu "error" primo do standardniho chyboveho vystupu.
void logErrors(String error, boolean log) {
if (log) {
System.err.println(error);
}
}
//===============================
Konec - Metody skriptu
==============================
// Vytvoření seznamu všech aktivních účtů.
// Proměnnou conn dodává konektor.
listOfIDs = listAllAccounts(conn);
Příklad 11.4. Skript listall.bsh
11.6.7. Skript SCHEMA
Název parametru
Typ parametru
Popis
conn
Connection
Objekt reprezentující JDBC
připojení k databázi
Tabulka 11.6. Parametry na vstupu skriptu SCHEMA
Skript na výstupu vrací mapu atributů a jejich typů na koncovém systému jako HashMap<String,
String>.
/*
Tento skript vrací mapu atributů a jejich typů na koncovém systému napojeném pomocí Universal
JDBC konektoru.
76
Skript GET
Zde jde o jednoduchou tabulku "accounts" obsahující sloupce "id", "firstname", "lastname" a
"state".
*/
import java.util.*;
final String DB_ACCOUNTS = "accounts";
final
final
final
final
String
String
String
String
COLUMN_ID = "id";
COLUMN_FIRST_NAME = "firstname";
COLUMN_LAST_NAME = "lastname";
COLUMN_STATE = "state;
//===============================
Metody skriptu
==============================
HashMap getSchema() {
HashMap names = new HashMap();
names.put(COLUMN_ID, "java.lang.Integer");
names.put(COLUMN_FIRST_NAME, "java.lang.String");
names.put(COLUMN_LAST_NAME, "java.lang.String");
names.put(COLUMN_STATE, "java.lang.String");
return names;
}
//===============================
Konec - Metody skriptu
// Vytvoření mapy atributů na koncovém systému
HashMap attributeNames = getSchema();
==============================
Příklad 11.5. Skript schema.bsh
11.6.8. Skript GET
Název parametru
Typ parametru
Popis
objClass
ObjectClass
Třída objektu, která je
skriptem spravována. Obvykle
ObjectClass.ACCOUNT
options
OperationOptions
Možnosti operace
conn
Connection
Objekt reprezentující JDBC
připojení k databázi
uid
Uid
Současný identifikátor objektu
Tabulka 11.7. Parametry na vstupu skriptu GET
Skript na výstupu vrací atributy na koncovém systému prostřednictvím instance třídy
ConnectorObject.
/*
Tento skript vrací účet na koncovém systému napojeném pomocí Universal JDBC konektoru.
Zde jde o jednoduchou tabulku "accounts" obsahující sloupce "id", "firstname", "lastname" a
"state".
Existující účet se nahraje do objektu třídy ConnectorObject s názvem "connectorObject", odkud
ho bude umět konektor přečíst.
*/
77
Kapitola 11. Identity Connectors
import
import
import
import
import
import
import
java.sql.Connection;
java.sql.Driver;
java.sql.DriverManager;
java.sql.ResultSet;
java.sql.SQLException;
java.sql.Statement;
java.sql.PreparedStatement;
import java.util.*;
import org.identityconnectors.framework.common.objects.*;
final String DB_ACCOUNTS = "accounts";
final String COLUMN_ID = "id";
final String COLUMN_FIRST_NAME = "firstname";
final String COLUMN_LAST_NAME = "lastname";
final String FIRST_NAME_ATTR = "jmeno";
final String LAST_NAME_ATTR = "prijmeni";
boolean loging = true;
// Only ACCOUNT is allowed.
if (!objClass.is(ObjectClass.ACCOUNT_NAME)) {
throw new IllegalArgumentException("Bad object type. Only ACCOUNT is supported.");
}
//===============================
Metody skriptu
==============================
// Vrátí ConnectorObject pro účet na koncovém systému s daným uid
ConnectorObject getUser(String uid, Connection connection) {
ConnectorObject connectorObject = null;
ConnectorObjectBuilder builder = null;
String statementAccount = "SELECT `"+COLUMN_ID+"`, `"+COLUMN_FIRST_NAME+"`,
`"+COLUMN_LAST_NAME+"` FROM `"+DB_ACCOUNTS+"` WHERE `"+COLUMN_ID+"` = ?;";
PreparedStatement existStmt = null;
ResultSet rs = null;
String firstName = null;
String lastName = null;
Collection attributesCol = null;
try {
// Nalezení objektu s daným UID
existStmt = connection.prepareStatement(statementAccount);
existStmt.setInt(1, Integer.parseInt(uid));
rs = existStmt.executeQuery();
if (!rs.next()) {
// Ucet neexistuje
return null;
}
builder = new ConnectorObjectBuilder();
attributesCol = new ArrayList();
// Získání hodnot atributů
firstName = rs.getString(COLUMN_FIRST_NAME);
lastName = rs.getString(COLUMN_LAST_NAME);
78
Skript SYNC
// Vytvoření objektů typu Attribute se získanými hodnotami a přidání do seznamu
attributesCol.add(AttributeBuilder.build(FIRST_NAME_ATTR, firstName));
attributesCol.add(AttributeBuilder.build(LAST_NAME_ATTR, lastName));
builder.addAttributes(attributesCol);
// Nastavíme třídu objektu UID, Name a vytvoříme objekt.
builder.setObjectClass(ObjectClass.ACCOUNT);
builder.setUid(uid);
builder.setName(uid);
connectorObject = builder.build();
} catch (Exception ex) {
logErrors(ex.getMessage(), loging);
throw new RuntimeException(ex.getMessage());
} finally {
if (existStmt != null) {
existStmt.close();
}
}
return connectorObject;
}
// Pokud je atribut TRUE, tak vypisuje zpravu "error" primo do standardniho chyboveho vystupu.
void logErrors(String error, boolean log) {
if (log) {
System.err.println(error);
}
}
//===============================
Konec - Metody skriptu
==============================
// Vytvoření objektu typu ConnectorObject s obsahem atributů koncového účtu.
// Proměnné uid a conn dodá konektor.
connectorObject = getUser(uid, conn);
Příklad 11.6. Skript get.bsh
11.6.9. Skript SYNC
Název parametru
Typ parametru
Popis
objClass
ObjectClass
Třída objektu, která je
skriptem spravována. Obvykle
ObjectClass.ACCOUNT
options
OperationOptions
Možnosti operace
conn
Connection
Objekt reprezentující JDBC
připojení k databázi
token
Token
Čas poslední synchronizace
Tabulka 11.8. Parametry na vstupu skriptu SYNC
Skript na výstupu vrací seznam instancí třídy ConnectorObject, který obsahuje všechny objekty
změněné od poslední synchronizace.
79
Kapitola 11. Identity Connectors
11.6.10. Skript GET_LAST_SYNC_TOKEN
Název parametru
Typ parametru
Popis
options
OperationOptions
Možnosti operace
conn
Connection
Objekt reprezentující JDBC
připojení k databázi
Tabulka 11.9. Parametry na vstupu skriptu GET_LAST_SYNC_TOKEN
Skript na výstupu vrací instanci třídy Token, který obsahuje čas poslední synchronizace.
11.7. Database Table konektor
Database Table konektor slouží k napojení jedné tabulky libovolné databáze. Standardně je uložen v
balíku org.identityconnectors.databasetable-XXX.jar.
Příkladem takového systému může být evidence zaměstnanců v personálním systému, kde všechna
data čteme a zapisujeme do jedné tabulky (případně jednoho view). Každý řádek tabulky je z pohledu
IdM jeden účet na koncovém systému.
Název parametru
Popis
Příklad hodnoty
Název systému
Výstižný název, pod kterým
se systém např. zobrazuje
uživatelům.
Personální systém
Pouze ke čtení
Zaškrtnutím této možnosti je
odškrtnuto
zajištěno, že na koncovém
systému nebude moci Identity
Manager nic vytvořit, změnit ani
smazat.
Authority level
Určuje prioritu systému.
Hodnota větší než 0 znamená,
že půjde o autoritativní
zdroj pro IdM; čím vyšší, tím
autoritativnější. Poznámka:
největší prioritu má IdM
repository.
0, nebo 1 pro autoritativní
zdroje
User Password
Heslo uživatele, s nímž se IdM
přihlašuje k databázi.
******
Table
Název napojované tabulky (jeli potřeba, tak včetně názvu
schématu).
VYMENIK.identity
Key Column
Název sloupce, který obsahuje
jednoznačný identifikátor účtu
(accountUid). Pomocí něj se
párují účty se řádky tabulky.
Typicky je to primární klíč
tabulky.
Id
JDBC Driver
Driver pro spojení s databází.
• oracle.jdbc.driver.OracleDriver
pro Oracle
80
Database Table konektor
Název parametru
Popis
Příklad hodnoty
• com.mysql.jdbc.Driver
pro MySQL
• org.firebirdsql.jdbc.FBDriver
pro Firebird
Datasource path
Něco specifického pro připojení
k Oracle.
[prázdné]
Validate Connection Query
Speciální příkaz pro otestování, [prázdné]
zda je spojení navázáno. Při
neuvedení se použije defaultní
testovací příkaz.
User
Login uživatele, s nímž se IdM
přihlašuje k databázi.
root
Rethrow all SQLExceptions
Odškrtnutím lze zajistit, že
SQL příkazy, které způsobují
SQLException s 0 Error Code,
budou odchyceny a potlačeny.
zaškrtnuto
All native
Zaškrtnutí způsobí, že všechny
datové typy sloupců tabulky
budou vraceny v nativním
formátu.
odškrtnuto
Name Quoting
Nastavuje znaky, mezi které se
budou vkládat názvy sloupců
(např. jednoduché uvozovky,
závorky,...) v posílaných SQL
příkazech.
[prázdné]
Password Column
Název sloupce, ve kterém se
ukládají hesla účtů uživatelů.
Nemusí být vyplněn, pokud se
hesla nemají ukládat.
[prázdné]
Port
Port, na kterém databázový
server naslouchá.
• 1521 pro Oracle
• 3306 pro MySQL
• 3051 pro Firebird
Native Timestamps
Zaškrtnutím lze zajistit, že se
bude datový typ Timestamp
vracet jako java.sql.Timestamp.
odškrtnuto
Enable writing empty string
Zaškrtnutí způsobí, že pro
odškrtnuto
sloupce s omezením not-null
se budou prázdné řetězce
zapisovat jako prázdné řetězce,
a ne NULL (což je defaultní
chování).
Initial JNDI Properties
Prostor pro nastavení
počátečního JDBC JNDI
[prázdné]
81
Kapitola 11. Identity Connectors
Název parametru
Popis
Příklad hodnoty
kontextu, ve formátu "klíč =
hodnota".
Host
Adresa databázového serveru
localhost
JDBC Connection URL
Template pro vytvoření url
pro JDBC konektor - za
hodnoty %h, %p a %d se
dosadí host, port a název
databáze. Umožňuje definovat
další vstupní hodnoty, např.
kódování.
• jdbc:oracle:thin:@%h:
%p:%d pro Oracle
• jdbc:mysql://
%h:%p/%d?
useUnicode=true&characterEncoding=UTFpro MySQL
• jdbc:firebirdsql:%h/
%p:%d pro Firebird
Change Log Column (Sync)
Název sloupce, který obsahuje
datum poslední změny na
řádku/účtu. Používá se při
synchronizaci s koncovým
systémem.
GREATEST_TIMESTAMP
Database
Název databáze.
personal_repository
Tabulka 11.10. Parametry systému napojeného pomocí Database Table konektoru
11.8. SSH konektor
Univerzální SSH konektor poskytuje možnosti pro připojení se k serveru prostřednictvím protokolu
SSH2. Konektor implementuje všechny potřebné metody pro správu identit na koncovém systému.
Koncovým systém může být buď přímo daný server, případně se může jednat o externí systém, který
na tomto serveru běží.
Realizace napojení koncového systému je rozdělena do dvou částí. První část tvoří samotný SSH
konektor. Druhou částí jsou skripty na daném serveru, které provádějí požadované operace nad
koncovým systémem. Tato architektura umožňuje použití konektoru k připojení k celé škály koncových
systémů. Stačí pouze pro každý systém vytvořit potřebné skripty dle daného rozhraní.
Atributy a všechny požadované informace jsou mezi konektorem a koncovými skripty předávány
ve formátu CSV nebo jako obyčejné textové řetězce. V této sekci je blíže popsáno, jak konektor
konfigurovat, jaké operace nad koncovým systémem jsou konektorem podporovány a příklady jejich
vstupů a výstupů.
11.8.1. Konfigurace konektoru
Konektor je standardně uložen v balíku org.identityconnectors.ssh-XXX.jar.
Název parametru
Popis
Status
Název systému
Výstižný název, pod kterým
se systém např. zobrazuje
uživatelům.
POVINNÉ
Pouze ke čtení
Zaškrtnutím této možnosti je
zajištěno, že na koncovém
systému nebude moci Identity
82
Skript Create
Název parametru
Popis
Status
Manager nic vytvořit, změnit ani
smazat.
Authority level
Určuje prioritu systému.
Hodnota větší než 0 znamená,
že půjde o autoritativní
zdroj pro IdM; čím vyšší, tím
autoritativnější. Poznámka:
největší prioritu má IdM
repository.
POVINNÉ
Password
Heslo uživatele, s nímž se IdM
přihlašuje na koncový systém.
NEPOVINNÉ
multi value attributes
Výčet multi-value atributů.
NEPOVINNÉ
Private key
Cesta k privátnímu klíči pro
přihlášení.
NEPOVINNÉ
Private key password
Heslo k privátnímu klíči.
NEPOVINNÉ
multi value attributes separator
Oddělovač použitý pro oddělení NEPOVINNÉ
vícehodnotových atributů.
escape mode
Escape mode (BACKSLASH
nebo DOUBLED).
POVINNÉ
Port
Číslo portu serveru, kde běží
SSH démon.
POVINNÉ
Host
Hostname serveru, kde běží
SSH démon.
POVINNÉ
Username
Uživatelské jméno pro
přihlášení se na koncový
systém.
POVINNÉ
Host key
Veřejný klíč serveru (pro
kontrolu otisku klíče při
přihlaš.).
NEPOVINNÉ
Tabulka 11.11. Parametry systému napojeného pomocí Univerzálního SSH konektoru
Dále se pro každou operaci nad koncovým systémem vyplní úplná cesta skriptu, který ji zpracovává.
Cesty k jednotlivým skriptům jsou sice nepovinné, ale pokud volaná metoda cestu ke skriptu potřebuje
a daná cesta není nastavena, dojde k vyhození odpovídající výjimky. To je uděláno z toho důvodu, aby
se nemusely nastavovat cesty ke skriptům pro metody, které nebudou používány.
11.8.2. Skript Create
Tato metoda slouží pro vytváření nových objektů na koncovém systému. V případě úspěšného
vytvoření nového objektu metoda navrací jeho jedinečný identifikátor (instance třídy Uid). Vytvářet se
mohou jak uživatelské účty (createUser), tak i uživatelské skupiny (createGroup).
Vstup
Množina atributů, které mají být propagovány na
koncový systém.
Výstup
AccountId nově vytvořené osoby.
83
Kapitola 11. Identity Connectors
Příklad vstupu
createUser
Name;EmailAddress;GECOS;Disabled
mucha8;[email protected];alfons;0
Příklad výstupu
AccountId user/64
Tabulka 11.12. Vstup a výstup skriptu createUser
11.8.3. Skript Update
Tato metoda slouží pro editaci stávajícího objektu. Požadovaný objekt je vybrán dle jeho jedinečného
identifikátoru (instance třídy Uid) a následně jsou u něho změněny požadované hodnoty. Metoda
závěrem navrací identifikátor změněného objektu (i identifikátor se může měnit). Editovat se mohou
jak uživatelské účty (updateUser), tak i uživatelské skupiny (updateGroup).
Vstup
Změněné hodnoty a AccountId účtu, kde se mají
změny provést.
Výstup
AccountId.
Příklad vstupu
updateUser AccountId;Disabled user/82;0
Příklad výstupu
AccountId user/82
Tabulka 11.13. Vstup a výstup skriptu updateUser
11.8.4. Skript Delete
Tato metoda slouží pro odstranění objektu na koncovém systému. Odpovídající objekt je určen dle
svého jedinečného identifikátoru. Odstraňovat se mohou jak uživatelské účty (deleteUser), tak i
uživatelské skupiny (deleteGroup).
Vstup
Pouze identifikátor daného účtu (parametr
AccountId), který se má smazat.
Výstup
Nic, pouze návratová hodnota funkce.
Příklad vstupu
deleteUser AccountId user/102
Příklad výstupu
Tabulka 11.14. Vstup a výstup skriptu deleteUser
11.8.5. Skript DisableUser
Tato metoda slouží pro zablokování uživatelského účtu. Blokaci účtu lze provést také prostřednictvím
funkce updateUser a atributu Disabled.
Vstup
AccountId účtu, který se má zamknout.
Výstup
Nic, pouze návratová hodnota funkce.
Příklad vstupu
disableUser AccountId user/64
Příklad výstupu
Tabulka 11.15. Vstup a výstup skriptu disableUser
11.8.6. Skript EnableUser
Tato metoda slouží pro odemčení uživatelského účtu. Odblokování účtu lze provést také
prostřednictvím funkce updateUser a atributu Disabled.
84
Skript ListObjects
Vstup
AccountId účtu, který se má odemknout.
Výstup
Nic, pouze návratová hodnota funkce.
Příklad vstupu
enableUser AccountId user/64
Příklad výstupu
Tabulka 11.16. Vstup a výstup skriptu enableUser
11.8.7. Skript ListObjects
Tato metoda slouží pro vypsání AccountId všech evidovaných osob.
Vstup
Pouze parametry příkazu, žádné hodnoty.
Výstup
AccountId všech uživatelů koncového systému.
Příklad vstupu
listObjects objectType Users
Příklad výstupu
AccountId user/1 user/10 user/25
Tabulka 11.17. Vstup a výstup skriptu listObjects
11.8.8. Skript AttributesSchema
Tato metoda navrací defaultní schéma atributů na koncovém systému, se kterými mohou pracovat
ostatní funkce.
Vstup
Pouze název funkce.
Výstup
Seznam podporovaných atributů (název + typ +
status, např. required).
Příklad vstupu
getAttributesSchema
Příklad výstupu
"Attribute_Name";"Type";"Flags"
"Name";"java.lang.String";"REQUIRED"
"EmailAddress";"java.lang.String";"REQUIRED"
"Password";"org.identityconnectors.common.security.GuardedS
"Comments";"java.lang.String";""
"Signature";"java.lang.String";""
"RealName";"java.lang.String";""
"Lang";"java.lang.String";""
"GECOS";"java.lang.String";""
"NickName";"java.lang.String";""
"Organization";"java.lang.String";""
Tabulka 11.18. Vstup a výstup skriptu attributesSchema
11.8.9. Příklad univerzálního skriptu
Všechny operace podporované SSH konektorem mohou být obsluhovány jedním skriptem. Níže je
uveden příklad univerzálního skriptu, který byl použit při napojení systému pro správu požadavků
Request Tracker pomocí SSH konektoru.
#!/bin/bash
85
Kapitola 11. Identity Connectors
# Tento skript slouzi pro praci s ucty na Request Trackeru verze 3.6.7, a to prostrednictvim
RT konzole.
# Autor: BCV solutions s.r.o.
############################################################################ KONFIGURACE
#
############################################################################
# Cesta k awk skriptu pro parsovani CSV
AWKCSV="/opt/rt_connector_scripts/csv.awk"
# Cesta ke skriptu pro spusteni RT konzole.
RTC="/data/rt4/bin/rt"
# Pouzivane programy (standardni linux distribuce)
AWK=/bin/awk
PERL="/usr/bin/perl -w"
# Konfiguracni informace o RT
export RTSERVER="http://servicedesk:8091/"
export RTUSER=root
export RTPASSWD=password
# Konfiguracni udaje k RT databazi (MySQL)
RTDBUSER=root
RTDBPASSWD=root
RTDBHOST=localhost
RTDBNAME=rt4
############################################################################
# Polozky vystupniho CSV
atAccountId="AccountId" # V RT odpovida "id".
atPassword="password" # V RT odpovida "Password".
# Polozky nazvy atributu vracene RT konzoli
rtAccountId="id" # V SSH konektoru odpovida "AccountId".
rtPassword="Password" # V SSH konektoru odpovida "password".
export PATH=/bin:/usr/bin:/sbin:/usr/sbin
# Zpracovani chyb
Error() {
cat - >&2
[ $# -ge 1 ] && exit $1
}
Log () {
Error
}
Debug() {
cat - >> /data/rt_conector_script.debug
}
# Zpracovani vstupnich dat, ktere jsou v CSV formatu.
zpracovatVstup() {
OIFS=$IFS;
IFS=\;
local radek=0
while read vstup; do
Debug <<< $vstup
radek=$((radek+1))
if [ ${radek} -eq 1 ]; then IDM_Prikaz=$vstup; fi
if [ ${radek} -eq 2 ]; then CSVH=( $vstup ); fi
86
Příklad univerzálního skriptu
if [ ${radek} -eq 3 ]; then
IFS=$OIFS
eval $($AWK -f $AWKCSV <<< ${vstup})
break
fi
# vic radku uz nebudeme nacitat i kdyby nam je IdM cpalo
# mozna by to chtelo kontrolovat a vracet chybu
done
#DEBUG: echo $IDM_Prikaz >> /ssh/vstup
IFS=$OIFS;
#zakladni kontrola vstupnich dat - hlavicka nesmi mit min sloupcu nez hodnoty
if [ ${#CSVV[*]} -gt ${#CSVH[*]} ]; then
Error 1 <<< "ERROR: Spatny format CSV dat $1."
fi
for i in $(seq 0 $((${#CSVH[*]} - 1))); do
eval "CSV_${CSVH[$i]}=\"${CSVV[$i]}\""
done
}
# Spusteni akce, kterou Identity Manager pozaduje
# - pro deaktivaci staci zakomentovat odpovidajici radek
spustitAkci() {
case "$1" in
("getUser") getUser ;;
("createUser") createUser ;;
("updateUser") updateUser ;;
("deleteUser") deleteUser ;;
("enableUser") enableUser ;;
("disableUser") disableUser ;;
# ("createGroup") createGroup ;;
# ("updateGroup") updateGroup ;;
# ("deleteGroup") deleteGroup ;;
("listObjects") listObjects ;;
# ("getGroup") getGroup ;;
(*) Error 1 <<< "ERROR: Nepodporovana akce $1." ;;
esac
}
# Spusti prikaz na RT konzoli.
runCmd () {
COMMAND="$PERL $RTC $@"
#Log <<< "Spusten prikaz: $COMMAND"
eval "$COMMAND"
}
# Spousti MySQL dotaz.
runMySQLQuery() {
#Log <<< "Spusten MySQL dotaz: $1"
unset result
result=`/usr/bin/mysql --user=$RTDBUSER --password=$RTDBPASSWD --host=$RTDBHOST --database=
$RTDBNAME -e "$1"`
echo "$result"
}
# Vraci seznam nastavenych atributu.
setAttributes() {
unset cName cEmailAddress cPassword cComments cSignature cRealName cLang cGECOS cNickName
cOrganization cHomePhone
unset cWorkPhone cMobilePhone cPagerPhone cAddress1 cAddress2 cCity cState cZip cCountry
cFreeformContactInfo
unset cEmailEncoding cWebEncoding cExternalContactInfoId cContactInfoSystem cExternalAuthId
cAuthSystem cTimezone cPGPKey
87
Kapitola 11. Identity Connectors
if [ "x$CSV_Name" != "x" ]; then cName="Name=\"${CSV_Name}\""; fi
if [ "x$CSV_EmailAddress" != "x" ]; then cEmailAddress="EmailAddress=
\"${CSV_EmailAddress}\""; fi
if [ "x$CSV_Password" != "x" ]; then cPassword="Password=\"${CSV_Password}\""; fi
if [ "x$CSV_Comments" != "x" ]; then cComments="Comments=\"${CSV_Comments}\""; fi
if [ "x$CSV_Signature" != "x" ]; then cSignature="Signature=\"${CSV_Signature}\""; fi
if [ "x$CSV_RealName" != "x" ]; then cRealName="RealName=\"${CSV_RealName}\""; fi
if [ "x$CSV_Lang" != "x" ]; then cLang="Lang=\"${CSV_Lang}\""; fi
if [ "x$CSV_GECOS" != "x" ]; then cGECOS="GECOS=\"${CSV_GECOS}\""; fi
if [ "x$CSV_NickName" != "x" ]; then cNickName="NickName=\"${CSV_NickName}\""; fi
if [ "x$CSV_Organization" != "x" ]; then cOrganization="Organization=
\"${CSV_Organization}\""; fi
if [ "x$CSV_HomePhone" != "x" ]; then cHomePhone="HomePhone=\"${CSV_HomePhone}\""; fi
if [ "x$CSV_WorkPhone" != "x" ]; then cWorkPhone="WorkPhone=\"${CSV_WorkPhone}\""; fi
if [ "x$CSV_MobilePhone" != "x" ]; then cMobilePhone="MobilePhone=\"${CSV_MobilePhone}\""; fi
if [ "x$CSV_PagerPhone" != "x" ]; then cPagerPhone="PagerPhone=\"${CSV_PagerPhone}\""; fi
if [ "x$CSV_Address1" != "x" ]; then cAddress1="Address1=\"${CSV_Address1}\""; fi
if [ "x$CSV_Address2" != "x" ]; then cAddress2="Address2=\"${CSV_Address2}\""; fi
if [ "x$CSV_City" != "x" ]; then cCity="City=\"${CSV_City}\""; fi
if [ "x$CSV_State" != "x" ]; then cState="State=\"${CSV_State}\""; fi
if [ "x$CSV_Zip" != "x" ]; then cZip="Zip=\"${CSV_Zip}\""; fi
if [ "x$CSV_Country" != "x" ]; then cCountry="Country=\"${CSV_Country}\""; fi
if [ "x$CSV_FreeformContactInfo" != "x" ]; then cFreeformContactInfo="FreeformContactInfo=
\"${CSV_FreeformContactInfo}\""; fi
if [ "x$CSV_EmailEncoding" != "x" ]; then cEmailEncoding="EmailEncoding=
\"${CSV_EmailEncoding}\""; fi
if [ "x$CSV_WebEncoding" != "x" ]; then cWebEncoding="WebEncoding=\"${CSV_WebEncoding}\""; fi
if [ "x$CSV_ExternalContactInfoId" != "x" ]; then
cExternalContactInfoId="ExternalContactInfoId=\"${CSV_ExternalContactInfoId}\""; fi
if [ "x$CSV_ContactInfoSystem" != "x" ]; then cContactInfoSystem="ContactInfoSystem=
\"${CSV_ContactInfoSystem}\""; fi
if [ "x$CSV_ExternalAuthId" != "x" ]; then cExternalAuthId="ExternalAuthId=
\"${CSV_ExternalAuthId}\""; fi
if [ "x$CSV_AuthSystem" != "x" ]; then cAuthSystem="AuthSystem=\"${CSV_AuthSystem}\""; fi
if [ "x$CSV_Timezone" != "x" ]; then cTimezone="Timezone=\"${CSV_Timezone}\""; fi
if [ "x$CSV_PGPKey" != "x" ]; then cPGPKey="PGPKey=\"${CSV_PGPKey}\""; fi
list="$cName $cEmailAddress $cPassword $cComments $cSignature $cRealName $cLang $cGECOS
$cNickName $cOrganization $cHomePhone $cWorkPhone $cMobilePhone $cPagerPhone $cAddress1
$cAddress2 $cCity $cState $cZip $cCountry $cFreeformContactInfo $cEmailEncoding $cWebEncoding
$cExternalContactInfoId $cContactInfoSystem $cExternalAuthId $cAuthSystem $cTimezone
$cPGPKey"
echo $list
}
# Funkce navraci vsechny identifikatory uzivatelskych uctu nebo skupin.
# Aktualne: Pouze uzivatelske ucty.
# STATUS: OK
listObjects() {
# Musi byt uveden typ pozadovaneho objektu
if [ "x${CSV_objectType}" == "x" ]; then
Error 100 <<< "ERROR: Nebyl zadan typ pozadovanych objektu."
fi
case "$CSV_objectType" in
("Users")
result=$(runMySQLQuery "SELECT id FROM Users;")
echo "$atAccountId"
#Odstranime hlavicku, tj. prvni radek vysledku, a pridame identifikator "user".
#result=`echo "$result" | sed 's/id//;s/\ /\nuser\//g' | sed '1d'`
result=`echo "$result" | sed '1d;s/^/user\//g'`
88
Příklad univerzálního skriptu
echo "$result"
;;
("Group")
Error 101 <<< "ERROR: Operace se skupinami nejsou zatim podporovany."
exit 0;
;;
(*) Error 102 <<< "ERROR: Nepodporovany typ objektu $CSV_objectType." ;;
esac
}
# Navraci udaje pro uzivatele s danym jmenem (vyhledavani dle id (id) nebo uzivatelskeho jmena
(Name))
# STATUS: OK
getUser() {
IFS=": "
# vyhledani udaju o danem uzivateli
if [ "x$CSV_AccountId" != "x" ]; then
userId=$CSV_AccountId
elif [ "x$CSV_Name" != "x" ]; then
userId=$CSV_Name
else
Error 110 <<< "ERROR: Nebylo zadano accountId ani Name."
fi
param="show -t user $userId"
output=<(
runCmd $param
if [ $? -ne 0 ]; then
Error 111 <<< "ERROR: Uzivatel $userId nebyl nalezen."
fi
)
local i=1
while read NAME VALUE; do
if [ "$i" -eq 1 ] && [ "$NAME" != "id" ]; then
# Neni asi lepsi moznost, jak detekovat to, ze uzivatel s danym jmenem neexistuje.
Error 111 <<< "ERROR: Uzivatel $userId nebyl nalezen."
fi
if [ "$NAME" == "$rtAccountId" ]; then
CSV_Header="$CSV_Header;$atAccountId" # Kvuli konektoru, tam je stanoveno, ze bude
"AccountId".
id="$VALUE"
elif [ "$NAME" == "$rtPassword" ]; then
# Heslo se nevraci, jako VALUE by se vratil obsah adresare, ve kterem je tento skript.
CSV_Header="$CSV_Header;$atPassword" # Kvuli konektoru, tam je stanoveno, ze bude
"password".
VALUE=""
else
CSV_Header="$CSV_Header;$NAME"
fi
# Eskejpovani - DOUBLED, tj. " misto ""
VALUE=`echo $VALUE | sed 's/"/""/'`
CSV_Values="$CSV_Values;\"$VALUE\""
i=$((i+1))
done < $output
# Zjistime status uzivatelskeho uctu (zamknuty nebo odemknuty).
id=`echo "$id" | sed 's/user\///'`
disabled=$(runMySQLQuery "SELECT Disabled FROM Principals WHERE id=$id;")
disabled=`echo $disabled | sed '1d'`
89
Kapitola 11. Identity Connectors
CSV_Header="$CSV_Header;Disabled"
CSV_Values="$CSV_Values;$disabled"
# Odstranime stredniky na zacatcich.
CSV_Header=`echo "$CSV_Header" | sed 's/;//'`
CSV_Values=`echo "$CSV_Values" | sed 's/;//'`
echo "$CSV_Header"
echo "$CSV_Values"
Debug <<< "getUser CSV_Header: ${CSV_Header}"
Debug <<< "getUser CSV_Values: ${CSV_Values}"
}
# Vytvari zaznam pro noveho uzivatele.
# STATUS: OK
createUser() {
if [ "x${CSV_Name}" == "x" ]; then
Error 120 <<< "ERROR: Nebylo zadano uzivatelske jmeno (Name)."
fi
list=$(setAttributes)
param="create -t user set $list"
IFS=""
# Spusteni prikazu a kontrola, zda byl uzivatel skutecne vytvoren.
Debug <<< "createUser param=${param}"
read output < <(runCmd $param)
text=`echo $output | sed 's/[0-9][0-9]*//'`
# Pokud nebyl uzivatelsky ucet zalozen, tak vypiseme odpovidajici chybu.
if [ "$text" != "# User created." ]; then
Error 121 <<< "ERROR: $output"
fi
# Uzivatelsky ucet byl vytvoren, navratime user ID.
id="user/`echo $output | sed 's/^[#a-zA-Z ]*//;s/[ a-zA-Z.]*$//'`"
echo "$atAccountId"
echo "$id"
# Zamknout ucet?
if [ "x$CSV_Disabled" == "x1" ]; then
# Zamkneme ucet
x=$(disableUser "$id")
fi
# Pokud nebylo stanoveno, ze bude zamcen, tak nic nedelame, tj. defaultne odemknut.
}
# Meni zaznam pro daneho uzivatele.
#
#STATUS: OK
updateUser() {
if [ "x$CSV_AccountId" != "x" ]; then
user=$(getUser $CSV_AccountId)
retCode=$?
else
Error 130 <<< "ERROR: Nebylo zadano accountId."
fi
# Uzivatel s danym AccountId nebo Name neexistuje.
if [ ${retCode} -ne 0 ]; then Error 131 <<< "ERROR: Uzivatel $CSV_AccountId neexistuje."; fi
list=$(setAttributes)
90
Příklad univerzálního skriptu
Debug <<< "updateUser list=${list}"
Debug <<< "updateUser CSV_Disabled=${CSV_Disabled}"
# Meni se nektere hodnoty atributu?
if [ "x$list" != "x" ]; then
IFS=""
param="edit -t user $CSV_AccountId set $list"
# Spusteni prikazu a kontrola, zda byl uzivatelsky ucet skutecne zmenen.
read output < <(runCmd $param)
text=`echo $output | sed 's/[0-9][0-9]*//'`
# Pokud nebyl uzivatelsky ucet zmenen, tak vypiseme odpovidajici chybu.
if [ "$text" != "# User updated." ]; then
Error 132 <<< "ERROR: $output"
fi
fi
if [ "x$CSV_Disabled" == "x1" ]; then
# Zamkneme ucet
x=$(disableUser $CSV_AccountId)
elif [ "x$CSV_Disabled" == "x0" ]; then
# Odemkneme ucet
x=$(enableUser $CSV_AccountId)
fi
echo "$atAccountId"
echo "$CSV_AccountId"
}
# Zablokovava uzivatelsky ucet pro dane user id.
# STATUS: OK
disableUser() {
if [ "x$1" != "x" ]; then
val=$1
elif [ "x${CSV_AccountId}" != "x" ]; then
val=$CSV_AccountId
else
Error 140 <<< "ERROR: Nebylo zadano accountId."
fi
# Parse user id. Potrebujeme pouze ciselnou hodnotu.
id=`echo $val | sed 's/user\///'`
runMySQLQuery "UPDATE Principals SET Disabled=1 WHERE id=$id;"
}
# Odblokovava uzivatelsky ucet pro dane user id.
# STATUS: OK
enableUser() {
if [ "x$1" != "x" ]; then
val=$1
elif [ "x${CSV_AccountId}" != "x" ]; then
val=$CSV_AccountId
else
Error 150 <<< "ERROR: Nebylo zadano accountId."
fi
# Parse user id. Potrebujeme pouze ciselnou hodnotu.
id=`echo $val | sed 's/user\///'`
runMySQLQuery "UPDATE Principals SET Disabled=0 WHERE id=$id;"
91
Kapitola 11. Identity Connectors
}
deleteUser() {
#Error 160 <<< "ERROR: Nepodporovana operace."
CSV_Disabled="1"
CSV_Name="$(date +%s)_USER_DELETED_${CSV_AccountId}"
CSV_EmailAddress="$(date +%s)_USER_DELETED_${CSV_AccountId}"
updateUser
}
Debug <<< "----- $(date) -----"
zpracovatVstup
spustitAkci "${IDM_Prikaz}"
Debug <<< "***** $(date) *****"
Příklad 11.7. Univerzální skript pro všechny operace SSH konektoru
92
Typické procesy správy životního cyklu
identit
Tato kapitola pojednává o typických procesech správy identit, které zajišťuje CzechIdM. Jednotlivé
procesy lze brát jako standardy při návrhu procesů pro nové zákazníky. Všechny níže popsané
procesy byly již implementovány v rámci předchozích projektů.
Na následující obrázku je diagram popisující vztahy mezi jednotlivými procesy. Stereotyp "CALL"
označuje vazbu, kde jeden proces (vychází z něho šipka) volá ve svém těle jiný proces (ten, ke
kterému směřuje šipka).
12.1. Závislosti mezi procesy
93
Kapitola 12. Typické procesy správy životního cyklu identit
12.2. Proces "Příchod zaměstnance"
12.2.1. Souhrn
Garant procesu
Personalista, vedoucí.
Základní povinnosti garantů procesu
Personalista: Zavedení nového zaměstnance do
personálního systému. Vedoucí: Vybrání rolí.
Vymezení platnosti procesu
Všechny osoby typu zaměstnanec.
Hlavní vstupy
Informace v personálním systému; vybrané role
vedoucím.
Hlavní výstupy
Založení účtů na systémech připojených k CzechIdM.
Založení identity zaměstnance v CzechIdM.
Zdroje informací
Personalista, vedoucí.
Měřitelná kritéria
Rychlost založení účtů na připojených systémech.
Tabulka 12.1. Příchod zaměstnance
12.2.2. Popis procesu "Příchod zaměstnance"
Proces je spouštěn v rámci synchronizace a je iniciován novým záznamem v personálním systému.
První akcí je načtení dat tohoto záznamu z personalistiky do IdM. Dle organizačního zařazení
zaměstnance se mu přidělí výchozí role, které se přidělují automaticky bez schvalování nebo
potvrzování vedoucím. Pokud čas nástupu nastal již v minulosti, tak se ihned vytvoří aktivovaná
uživatelská identita v IdM (zároveň s účty na koncových systémech definovaných výchozími
rolemi). Jestliže je nástup až v budoucnosti, tak se také vytvoří identita a výchozí uživatelské
účty, ale zablokují se. V obou případech se dále vygeneruje uživatelův email, který se zapíše do
personálního systému (v personálním systému je zablokována možnost email měnit). Dále se
vygeneruje informativní email, který obsahuje informace o přidělených oprávněních na konkrétní
koncové systémy, vygenerovaná výchozí hesla, případně další informativní údaje potřebné pro
nově příchozího zaměstnance. Tento email se poté odešle vedoucímu zaměstnance (pokud má
zaměstnanec přiřazeno více pracovních pozic, tak se odešle vedoucímu hlavní pracovní role, tj. s
nejnižším pořadovým číslem). Dále jsou všichni vedoucí nového zaměstnance vyzváni pro přidělení
případných dalších rolí. To je již však součástí navazujícího procesu "Přidat oprávnění uživateli".
Tento proces může být také spuštěn z procesu "Změna popisných dat uživatele", a to v případě
nástupu zaměstnance, který již ve společnosti dříve pracoval. Záznamy o zaměstnancích v
personálním systému totiž zůstávají i po jejich odchodu ze společnosti (u záznamu je pouze
nastaven příznak "aktivni" na FALSE). V případě opětovného nástupu zaměstnance se tedy v
personálním systému nevytváří nový záznam pro zaměstnance, ale nastaví se pouze u stávajícího
záznamu příznak "aktivni" na TRUE. Stejně jako personální systém, tak i CzechIdM nemaže po
odchodu zaměstnance jeho identitu. V případě opětovného nástupu zaměstnance tedy CzechIdM
při synchronizaci dle příznaku "aktivni" zjistí, že nastupuje zaměstnanec, který již ve společnosti
dříve pracoval, a aktivuje příslušnou identitu (pokud příslušná identita neexistuje, tak vytvoří novou).
Ostatní kroky procesu "Příchod zaměstnance" jsou již stejné jako při standardním nástupu nového
zaměstnance. Jen není potřeba generovat pro zaměstnance emailovou adresu, protože ta je již byla
vygenerována při jeho prvním nástupu.
94
Diagram
12.2.3. Diagram
95
Kapitola 12. Typické procesy správy životního cyklu identit
12.3. Proces "Přidat oprávnění uživateli"
12.3.1. Souhrn
Garant procesu
Vedoucí, admin IdM, help-desk, schvalovatel.
Základní povinnosti garantů procesu
Vedoucí, admin IdM, help-desk: Vybrat uživatele
(případně jeho pracovní pozici), vybrat mu role
a potvrdit přidělení rolí. Schvalovatel: Schválení
požadované role (v případě, že má daná role
schvalovatele).
Vymezení platnosti procesu
Všichni uživatelé (zaměstnanci i externisté).
Hlavní vstupy
Ruční vyžádání role pro daného uživatele.
Hlavní výstupy
Přiřazení rolí uživateli (přiřazení oprávnění).
Zdroje informací
Vedoucí, admin IdM, help-desk, schvalovatel.
Měřitelná kritéria
Rychlost založení účtů na koncových zařízeních
definovaných požadovanými rolemi.
Tabulka 12.2. Přidat oprávnění uživateli
12.3.2. Popis procesu "Přidat oprávnění uživateli"
Tento proces popisuje způsob, jakým budou uživatelům přidělovány role definující oprávnění na
koncové systémy a na adresáře souborového systému. Přidělení oprávnění mohou pro uživatele
požadovat jeho vedoucí, pracovníci help-desku, administrátoři IdM a dokonce sám uživatel si může
požádat o přidělení oprávnění. Pokud oprávnění pro zaměstnance požaduje někdo jiný než jeho
vedoucí, tak je nutné, aby žádost o přiřazení oprávnění vedoucí potvrdil. Oprávnění se přidělují na
úrovni pracovních pozic zaměstnance. Při žádosti se tedy musí vybrat pracovní pozice zaměstnance,
pro kterou se žádá o dané oprávnění. Tím se určí odpovídající vedoucí, na kterého jde potvrzení
pro přidělení oprávnění (dle příslušnosti pracovní pozice do organizačního subjektu). To je nutné z
toho důvodu, že zaměstnanec může mít obecně více pracovních pozic. Na rozdíl od zaměstnanců,
externisté nemají pracovní pozice. Nemají tedy ani vedoucí. Proto u externistů potvrzuje žádosti
administrátoři IdM.
Pokud má navíc role definující dané oprávnění přiřazeného schvalovatele (může jich mít i více),
tak je nutné schválení alespoň jednoho ze schvalovatelů. Po schválení role schvalovatelem je již
možné přiřadit uživateli (ať již zaměstnanci či externistovi) dané oprávnění. O přidělení oprávnění je
uživatel notifikován emailem. Pokud je daným uživatelem osoba typu zaměstnance, tak je o přiřazení
oprávnění zaměstnanci notifikován vedoucí dané pracovní pozice, pro kterou je oprávnění přiřazeno.
V případě externistů jsou notifikováni administrátoři IdM.
Tento proces může být také spuštěn automaticky z procesů "Příchod zaměstnance" a "Změna
pracovní pozice". V tomto případě se přeskakuje fáze vybírání identity (případně pracovní pozice), ale
rovnou se přistupuje k výběru rolí pro přidání oprávnění.
96
Diagram
12.3.3. Diagram
12.4. Proces "Odebrat oprávnění uživateli"
12.4.1. Souhrn
Garant procesu
Vedoucí, admin IdM, help-desk.
Základní povinnosti garantů procesu
Vedoucí, admin IdM, help-desk: Vybrat uživatele
(případně jeho pracovní pozici), vybrat role pro
odstranění, potvrdit odstranění rolí.
Vymezení platnosti procesu
Všichni uživatelé (zaměstnanci i externisté).
Hlavní vstupy
Vybrané role pro odstranění u daného uživatele.
97
Kapitola 12. Typické procesy správy životního cyklu identit
Hlavní výstupy
Odebrané role u uživatele (odebraná oprávnění).
Zdroje informací
Vedoucí, admin IdM, help-desk.
Měřitelná kritéria
Rychlost odebrání oprávnění na příslušných účtech
koncových systémů (případně zrušení daných účtů).
Tabulka 12.3. Odebrat oprávnění uživateli
12.4.2. Popis procesu "Odebrat oprávnění uživateli"
Tento proces popisuje odebírání oprávnění uživatelům. Jak již bylo řečeno, oprávnění na koncové
systémy a na adresáře souborového serveru jsou reprezentovány pomocí rolí. Pro odebrání
přiděleného oprávnění uživateli je potřeba mu odebrat příslušnou roli. Odebírat oprávnění (role)
mohou vedoucí (pouze pro své podřízené), pracovníci help-desku (pro všechny uživatele) a
administrátoři IdM.
Prvním krokem procesu je výběr identity uživatele, kterému se mají odstranit některé role. Pokud se
jedná o zaměstnance, tak se dále vybere pracovní pozice, pro kterou se mají odstranit některé role.
V případě externistů se pokračuje dále (žádné pracovní pozice nemají). Následuje výběr rolí, které
se mají odstranit, a potvrzení jejich odstranění. Poté se role již odstraní. Pokud se odstraní poslední
role definující přístup na některý z koncových systémů, tak se odstraní i uživatelův účet na daném
systému. Posledním krokem je notifikace uživatele o odstranění některých práv. V případě, že daným
uživatelem je osoba typy zaměstnanec, tak je notifikován vedoucí pracovní pozice, pro kterou jsou
odebírána oprávnění. Pokud je uživatelem externista, tak jsou notifikováni administrátoři IdM.
I tento proces může být spuštěn z jiného procesu, konkrétně z procesu "Změna pracovní pozice".
V tom případě se přeskakují fáze, ve které se vybírá identita uživatele (případně i pracovní pozice).
Pokračuje se tedy výběrem rolí k odstranění.
98
Diagram
12.4.3. Diagram
12.5. Proces "Povolení systémů"
12.5.1. Souhrn
Garant procesu
Vedoucí, administrátor IdM, help-desk.
Základní povinnosti garantů procesu
Vedoucí, administrátor IdM, help-desk: Vybrání
zablokované identity uživatele a potvrzení jejího
odblokování (spolu se všemi zablokovanými účty
uživatele na koncových systémech).
Vymezení platnosti procesu
Všichni uživatelé (zaměstnanci i externisté).
Hlavní vstupy
Vybraná zablokovaná identita uživatele.
Hlavní výstupy
Odblokování identity uživatele a odblokování všech účtů
uživatele na koncových systémech.
Zdroje informací
Vedoucí, administrátor IdM, help-desk.
Měřitelná kritéria
Rychlost odblokování identity a všech účtů uživatele na
koncových systémech.
Tabulka 12.4. Povolení systémů
99
Kapitola 12. Typické procesy správy životního cyklu identit
12.5.2. Popis procesu "Povolení systémů"
Tento proces slouží k odblokování zablokované identity uživatele a k odblokování účtů uživatele
na koncových systémech připojených k CzechIdM. Odblokovat zablokované účty mohou pouze
vedoucí (mohou odblokovat pouze účty svých podřízených), pracovníci help-desku a administrátoři
IdM. Pracovníci help-desku a administrátoři IdM mohou odblokovat účty libovolnému uživateli. Po
odblokování účtů a identity je daný uživatel o této skutečnosti notifikován. V případě, že daným
uživatelem je zaměstnanec, tak jsou notifikováni všichni jeho vedoucí. V případě externisty jsou
notifikováni administrátoři IdM.
Tento proces může být inicializován také z procesů "Provedení časované události" a "Vyjmutí z
karantény". Z procesu "Provedení časované události" se volá v tom případě, když nastalo datum
nástupu zaměstnance. Datum nástupu zaměstnance může být totiž nastaveno na budoucí datum.
V tom případě se v rámci procesu "Příchod zaměstnance" vytvoří zaměstnancova identita a účty na
systémech definovaných výchozími rolemi a rolemi specifikovanými vedoucím (vedoucími) daného
zaměstnance. Identita a účty se však vytvoří zablokované. Zároveň se také vytvoří časovač, který
expiruje k datu nástupu daného zaměstnance. Když nastane datum nástupu zaměstnance (expirace
časovače), tak proces "Provedení časované události" odblokuje identitu a všechny zaměstnancovy
účty právě pomocí procesu "Povolení systémů".
Z procesu "Vyjmutí z karantény" je tento proces volán proto, aby se opětovně aktivovaly přístupy k
účtům a k identitě zaměstnance, jehož účty byly v karanténě. Proces "Vyjmutí z karantény" se volá
například v tom případě, když účty zaměstnance jsou již v karanténě a zároveň se posune datum
odchodu zaměstnance na budoucí datum.
12.5.3. Diagram
100
Proces "Zakázání systémů"
12.6. Proces "Zakázání systémů"
12.6.1. Souhrn
Garant procesu
Vedoucí, administrátor IdM, help-desk.
Základní povinnosti garantů procesu
Vedoucí, administrátor IdM, help-desk: Vybrání identity
uživatele a potvrzení její zablokování (spolu se všemi
účty uživatele na koncových systémech).
Vymezení platnosti procesu
Všichni uživatelé (zaměstnanci i externisté).
Hlavní vstupy
Vybraná identita uživatele.
Hlavní výstupy
Zablokování identity uživatele a všech jeho účtů na
koncových systémech.
Zdroje informací
Vedoucí, administrátor IdM, help-desk.
Měřitelná kritéria
Rychlost zablokování identity a všech účtů uživatele na
koncových systémech.
Tabulka 12.5. Zakázání systémů
12.6.2. Popis procesu "Zakázání systémů"
Proces "Zakázání systémů" slouží k zablokování identity a účtů na koncových systémech pro daného
uživatele. Zablokovat identitu uživatele a jeho účty na koncových systémech mohou vedoucí (pouze
u svých podřízených), pracovníci help-desku (u všech uživatelů) a administrátoři CzechIdM. O
zablokování identity a účtů jsou v případě zaměstnance notifikováni jeho vedoucí, v případě externistů
jsou notifikováni administrátoři IdM.
Tento proces může být spuštěn také z procesů "Vyjmutí z evidenčního počtu" a "Ukončení PPV".
101
Kapitola 12. Typické procesy správy životního cyklu identit
12.6.3. Diagram
12.7. Proces "Změna popisných dat uživatele"
12.7.1. Souhrn
Garant procesu
Personalista, vedoucí, help-desk, administrátor IdM.
Základní povinnosti garantů procesu
Personalista: Aktualizace údajů zaměstnance v
personálním systému. Vedoucí, help-desk, administrátor
IdM: Ruční aktualizace popisných dat v CzechIdM.
Vymezení platnosti procesu
Všichni uživatelé (zaměstnanci i externisté).
Hlavní vstupy
Změněný záznam zaměstnance v personálním
systému. Změněná data u uživatele přímo v CzechIdM.
Hlavní výstupy
Aktualizace identity uživatele a propagace změněných
hodnot na účty uživatele na koncových systémech.
Zdroje informací
Personální systém, vedoucí, help-desk, administrátor
IdM.
Měřitelná kritéria
Rychlost propagace změněných atributů na koncové
systémy, případně rychlost založení účtů na koncových
systémech.
Tabulka 12.6. Změna popisných dat uživatele
102
Popis procesu "Změna popisných dat uživatele"
12.7.2. Popis procesu "Změna popisných dat uživatele"
Proces je spouštěn během synchronizace v okamžiku, kdy CzechIdM zjistí změnu záznamu v
personálním systému oproti repository CzechIdM. Změny mohou být také prováděny přímo v
CzechIdM. Podle druhu provedené změny se potom spustí odpovídající proces.
Pokud dojde u záznamu zaměstnance v personálním systému ke změně příznaku "aktivni" z
FALSE na TRUE, tak se spustí proces "Příchod zaměstnance". Tato situace nastane, pokud do
společnosti nastupuje zaměstnanec, který zde již pracoval. Záznamy v personálním systému se
totiž nemažou, takže při opětovném nástupu se v personálním systému nevytváří nový záznam
zaměstnance. Pouze se záznam zaměstnance aktivuje nastavením příznaku "aktivni" na TRUE.
Pokud neexistuje odpovídající identita v CzechIdM, tak ji proces "Příchod zaměstnance" vytvoří. Dále
proces "Příchod zaměstnance" pokračuje standardně, až na to, že se negeneruje emailová adresa (ta
je již v personalistice uložena z předchozího pracovního poměru).
V případě změny obyčejných popisných atributů je spuštěn proces "Změna uživatelských atributů".
Tento proces nastavuje atributům v CzechIdM nové hodnoty a zajišťuje propagaci nových hodnot na
účty uživatele na koncových systémech. Pokud navíc dojde ke změně příjmení, tak se vygeneruje
emailový alias, který bude přesměrovávat poštu do původní schránky.
Pokud došlo v personálním systému ke změně u pracovních pozic, tak je automaticky spuštěn proces
"Změna pracovní pozice". Změnou může být přidání pracovní pozice zaměstnanci nebo odebrání
pracovní pozice zaměstnanci.
Dalším možným procesem spustitelným z tohoto procesu je proces "Vyjmutí z evidenčního počtu". Ten
je spuštěn v tom případě, kdy u záznamu zaměstnance v personálním systému je nastaven příznak
"vyjmuti_z_evidencniho_poctu" na TRUE.
Z tohoto procesu může být spuštěn také proces "Vyjmutí z karantény". Tento proces se spouští v tom
případě, kdy zaměstnancova identita a jeho účty jsou v karanténě a zároveň se mu posune datum
odchodu na budoucí datum. V tom případě je potřeba zablokované účty a identitu do daného data
povolit, a právě k tomu slouží proces "Vyjmutí z karantény".
Posledním procesem, který může být spuštěn z procesu "Změna popisných dat uživatele" je proces
"Ukončení PPV". Ten slouží k nastavení karantény na zaměstnancovu identity a účty na koncových
systémech. Pokud bude nastaveno datum odchodu zaměstnance na aktuální datum nebo datum v
minulosti, tak se nebude vytvářet časovač, který by spustil proces "Ukončení PPV" k datu odchodu
zaměstnance, ale proces "Ukončení PPV" se spustí rovnou z tohoto procesu. Hlavní výhodou je to, že
se identita a účty dostanou do karantény rychleji (není potřeba vytvářet časovač).
103
Kapitola 12. Typické procesy správy životního cyklu identit
12.7.3. Diagram
12.8. Proces "Změna uživatelských atributů"
12.8.1. Souhrn
Garant procesu
Personalista, help-desk, administrátor IdM.
Základní povinnosti garantů procesu
Personalista: Změna uživatelských atributů v
personálním systému. Help-desk: Změna hesla
104
Popis procesu "Změna uživatelských atributů"
uživatele v CzechIdM. Administrátor IdM: Změna
atributů přímo v CzechIdM.
Vymezení platnosti procesu
Všichni uživatelé (zaměstnanci i externisté).
Hlavní vstupy
Změna uživatelských atributů oproti aktuálnímu stavu.
Hlavní výstupy
Aktualizované atributy u identity a u účtů na koncových
systémech.
Zdroje informací
Personální systém, help-desk a administrátor IdM.
Měřitelná kritéria
Rychlost propagace změněných atributů na účty na
koncových systémech.
Tabulka 12.7. Změna uživatelských atributů
12.8.2. Popis procesu "Změna uživatelských atributů"
Tento proces provádí změnu atributů u identity uživatele dle aktuálních dat v personálním systému.
Změny mohou být také provedeny ručně v CzechIdM. Tento proces potom nastaví odpovídajícím
atributům nové hodnoty a ty také propaguje na uživatelovy účty na koncových systémech.
12.8.3. Diagram
12.9. Proces "Změna pracovní pozice"
12.9.1. Souhrn
Garant procesu
Personalista, vedoucí.
Základní povinnosti garantů procesu
Personalista: Přidat nebo odebrat pracovní pozici
zaměstnanci. Přesunout org. subjekt s danou pracovní
pozicí. Vedoucí: Přiřazení případných dalších rolí při
přidání pracovní pozice. Vybrání a odstranění rolí při
odstranění pracovní pozice.
105
Kapitola 12. Typické procesy správy životního cyklu identit
Vymezení platnosti procesu
Všechny osoby typu zaměstnanec.
Hlavní vstupy
Informace v personálním systému. Vedoucím vybrané
role.
Hlavní výstupy
Aktualizace pracovních pozic zaměstnance.
Zdroje informací
Personalista, vedoucí.
Měřitelná kritéria
Rychlost propagace změněných oprávnění
zaměstnance na jeho účty na koncových systémech.
Tabulka 12.8. Změna pracovní pozice
12.9.2. Popis procesu "Změna pracovní pozice"
Tento proces je spouštěn z procesu "Změna popisných dat uživatele" v případě, že dojde ke změně
pracovních pozic u zaměstnance. Tento proces provedené změny vyhodnotí a propaguje dále. Pokud
je zaměstnanci přiřazena další pracovní pozice, tak mu jsou automaticky přidělena výchozí práva a
automaticky se mu vytvoří účty na koncových systémech, kam má nově dle oprávnění přístup. Dále
je spuštěn proces "Přidat oprávnění uživateli", aby mohl vedoucí danému zaměstnanci přiřadit další
případná oprávnění.
Pokud je zaměstnanci odebrána pracovní pozice, tak se spustí proces "Odebrat oprávnění uživateli",
kde vedoucí dané pracovní pozice (dle org. subjektu) specifikuje oprávnění (role), které se mají
zaměstnanci odebrat.
Poslední možností je přesun pracovní pozice. To je situace, kdy je v personálním systému přesunut
organizační subjekt, který obsahuje danou pracovní pozici. V tom případě se spustí proces "Přesun
pracovní pozice".
106
Diagram
12.9.3. Diagram
12.10. Proces "Vyjmutí z evidenčního počtu"
12.10.1. Souhrn
Garant procesu
Vedoucí hlavní pracovní pozice.
Základní povinnosti garantů procesu
Vedoucí hlavní pracovní pozice:
Vymezení platnosti procesu
Všechny osoby typu zaměstnanec.
Hlavní vstupy
Informace v personálním systému; Vedoucím nebo
administrátorem IdM vybrané role.
Hlavní výstupy
Aktualizace účtů na systémech připojených k IdM.
Zdroje informací
Personální systém, vedoucí a admin IdMs.
Měřitelná kritéria
Rychlost aktualizace účtů na připojených systémech.
Případně rychlost založení či zrušení účtů.
Tabulka 12.9. Vyjmutí z evidenčního počtu
12.10.2. Popis procesu "Vyjmutí z evidenčního počtu"
Tento proces je spouštěn pouze z procesu "Změna popisných dat uživatele". Slouží k tomu, aby
se zablokovaly účty zaměstnance, pokud má být zaměstnanec delší dobu nepřítomen, například z
107
Kapitola 12. Typické procesy správy životního cyklu identit
důvodu dlouhodobé nemoci či mateřské dovolené. V personálním systému personalista nastaví u
záznamu daného zaměstnance příznak "vyjmuti_z_evidencniho_poctu" na TRUE. Při synchronizaci
CzechIdM s personálním systémem je tato změna zjištěna v rámci procesu "Změna popisných dat
uživatele", kde dojde ke spuštění procesu "Vyjmutí z evidenčního počtu". Tento proces vyhledá
všechny role definující oprávnění zaměstnance na účty na koncových systémech. Vedoucí hlavní
pracovní pozice poté rozhodne, které účty se mají pomocí procesu "Zakázání systémů" zablokovat.
Nakonec jsou vedoucí všech pracovních pozic zaměstnance notifikováni o zablokování daných účtů
zaměstnance.
Při návratu zaměstnance do společnosti je potřeba v personálním systému zrušit příznak
"vyjmuti_z_evidencniho_poctu" a povolit zaměstnanci zablokované účty.
12.10.3. Diagram
12.11. Proces "Přesun pracovní pozice"
12.11.1. Souhrn
Garant procesu
Vedoucí.
Základní povinnosti garantů procesu
Vedoucí: Výběr rolí, které se odstraní u přesouvané
pracovní pozice.
Vymezení platnosti procesu
Všichni zaměstnanci.
Hlavní vstupy
Informace v personálním systému o přesouvané
pracovní pozici. Vedoucím vybrané role pro odstranění
u dané pracovní pozice.
Hlavní výstupy
Aktualizovaná oprávnění zaměstnance, jenž má
přidělenou danou pracovní pozici.
108
Popis procesu "Přesun pracovní pozice"
Zdroje informací
Personální systém, vedoucí.
Měřitelná kritéria
Rychlost změny oprávnění u dané pracovní pozice.
Tabulka 12.10. Přesun pracovní pozice
12.11.2. Popis procesu "Přesun pracovní pozice"
Tento proces je volán z procesu "Změna pracovní pozice". Nejdříve se určí role, které se dané
pracovní pozici přiřadí automaticky. Role, které přesunem organizačního subjektu přestanou u
dané pozice platit, nemohou být přímo odstraněny. Jejich odstranění musí být potvrzeno vedoucím
přesouvaného org. subjektu (vedoucím dané pracovní pozice). Vedoucí tedy vybere role, které se u
dané pracovní pozice odstraní a potvrdí jejich smazání. Po odstranění vybraných rolí se propagují
změny na koncové systémy daného zaměstnance. Nakonec je příslušný zaměstnanec a jeho vedoucí
notifikován o změně organizačního subjektu a přidělených práv.
12.11.3. Diagram
109
Kapitola 12. Typické procesy správy životního cyklu identit
12.12. Proces "Provedení časované události"
12.12.1. Souhrn
Garant procesu
Žádný.
Základní povinnosti garantů procesu
Nic.
Vymezení platnosti procesu
Tento proces pracuje pouze s uživateli typu
zaměstnanec.
Hlavní vstupy
Vypršená časovaná událost.
Hlavní výstupy
Spuštění odpovídajícího navazujícího procesu.
Zdroje informací
Personální systém.
Měřitelná kritéria
Rychlost spuštění navazujícího procesu.
Tabulka 12.11. Provedení časované události
12.12.2. Popis procesu "Provedení časované události"
Jedná se o interní proces systému CzechIdM. Tento proces reaguje na nastalou časovanou událost.
Nejdříve zjistí, jaká událost nastala. V úvahu připadají 3 možnosti:
• Nastalo datum ukončení PPV pro některého ze zaměstnanců - v tomto případě je spuštěn proces
"Ukončení PPV", jehož úkolem je dále nastavení karantény na účty odcházejícího zaměstnance atd.
• Vypršela karanténa na identitu - v případě, že časovaná událost značí to, že vypršela karanténa
zaměstnanecké identity, tak se dále spustí proces "Smazání identity". Ten smaže identity
zaměstnance a všechny jeho účty na koncových systémech.
• Nastalo datum nástupu - v případě, že nastalo datum nástupu zaměstnance, tak se spustí proces
"Povolení systémů", který odblokuje již vytvořené účty pro daného zaměstnance (účty se vytváří již
při příchodu zaměstnance do společnosti).
110
Diagram
12.12.3. Diagram
12.13. Proces "Ukončení PPV"
12.13.1. Souhrn
Garant procesu
Žádný.
Základní povinnosti garantů procesu
Nic.
Vymezení platnosti procesu
Všechny osoby typu zaměstnanec.
Hlavní vstupy
Informace v personálním systému. Datum ukončení
PPV u daného zaměstnance.
Hlavní výstupy
Zablokování identity a všech účtů zaměstnance.
Zdroje informací
Personální systém.
Měřitelná kritéria
Rychlost zablokování všech účtů zaměstnance.
Tabulka 12.12. Ukončení PPV
12.13.2. Popis procesu "Ukončení PPV"
Tento proces se vždy spouští pouze z procesů "Provedení časované události" nebo "Změna popisných
dat uživatele", a týká se pouze osob typu zaměstnanec. Žádný z uživatelů CzechIdM nemůže tento
proces inicializovat přímo.
Nejdříve se nastaví příznak vložení do karantény u identity daného zaměstnance a poté se zablokují
všechny zaměstnancovi účty na koncových systémech. Závěrem se všem vedoucím daného
zaměstnance odešle informativní email s informacemi o tom, že zaměstnancovi účty byly zablokovány.
111
Kapitola 12. Typické procesy správy životního cyklu identit
12.13.3. Diagram
12.14. Proces "Smazání uživatele"
12.14.1. Souhrn
Garant procesu
Administrátor IdM.
Základní povinnosti garantů procesu
Administrátor IdM: Vybrání uživatele, jehož identita a
účty na koncových systémech budou smazány.
Vymezení platnosti procesu
Všichni uživatelé (zaměstnanci i externisté).
Hlavní vstupy
Výběr uživatele pro smazání.
Hlavní výstupy
Smazána identita uživatele, smazány účty uživatele na
koncových systémech.
Zdroje informací
Personální systém, administrátor IdM.
Měřitelná kritéria
Rychlost smazání identity a účtů na koncových
systémech.
Tabulka 12.13. Smazání uživatele
12.14.2. Popis procesu "Smazání uživatele"
Tento proces může být spuštěn v rámci procesu "Provedení časované události" nebo přímou akcí
administrátora IdM v CzechIdM. Prvním krokem je vybrání uživatele, jehož identita a účty se mají
smazat. Pokud je tento proces spouštěn z procesu "Provedení časované události", tak se tento krok
přeskakuje, tj. uživatel je vybrán již dříve. V následujícím kroku se vyhledají všechny uživatelovi
role, které mu definují účty na koncových systémech. Dále se všechny tyto účty smažou a spolu
s nimi i identita uživatele v CzechIdM. Smazání účtů uživatele je trvalé, tj.bez použití zálohy není
možné obnovit stav před smazáním. U identit uživatelů je však situace jiná. Identity se mažou pouze
příznakem (označení, že identita je smazána, ale ve skutečnosti je stále v repository CzechIdM). To
je nutné z důvodu možného nástupu zaměstnance, který již ve společnosti dříve pracoval. V tomto
případě se nebude vytvářet nová identita, ale aktivuje se ta dřívější (zaměstnanec tedy bude mít stejný
112
Diagram
email, co měl dříve), viz. proces "Příchod zaměstnance". Posledním krokem je notifikace o smazání
identity a účtů daného uživatele. V případě, že uživatelem je zaměstnanec, tak jsou notifikováni jeho
vedoucí, v případě externistů jsou notifikováni administrátoři CzechIdM.
12.14.3. Diagram
12.15. Proces "Vyjmutí z karantény"
12.15.1. Souhrn
Garant procesu
Žádný.
Základní povinnosti garantů procesu
Nic.
Vymezení platnosti procesu
Všechny osoby typu zaměstnanec.
Hlavní vstupy
Vybraná identita v karanténě, odstraněno (posunuto)
datum ukončení PPV.
Hlavní výstupy
Odblokování identity a účtů zaměstnance.
Zdroje informací
Personální systém.
Měřitelná kritéria
Rychlost odblokování všech účtů zaměstnance a jeho
identity v CzechIdM.
Tabulka 12.14. Vyjmutí z karantény
113
Kapitola 12. Typické procesy správy životního cyklu identit
12.15.2. Popis procesu "Vyjmutí z karantény"
Proces "Vyjmutí z karantény" může být spuštěn pouze z procesu "Změna popisných dat uživatele",
a to v tom případě, když je zaměstnancova identita v karanténě a zároveň je odstraněno (nebo
posunuto do budoucna) datum odchodu zaměstnance. V tom případě se odblokuje identita
zaměstnance a všechny jeho účty na koncových systémech. Poté jsou o vyjmutí zaměstnance z
karantény notifikováni vedoucí pracovních pozic zaměstnance.
12.15.3. Diagram
12.16. Obecné řešení karantény
Na třídě Data jsou metody quarantineBegin a quarantineEnd. Těmito metodami je možné vložit
identitu do karantény nebo ji z karantény vyjmout. Karanténa v tomto případě znamená pouze
nastavení příznaku, že je identita v karanténě, a data, kdy byla do karantény vložena.
Administrátor může v administrátorském rozhraní nastavit do pravidelně spouštěných úloh
workflow quarantine.process. To projde všechny identity v CzechIdM a zjistí, zda nejsou v
karanténě déle, než je stanovenž čas. Délka karantény může být stanovena na jiný počet dnů
u každé organizace (přes možnost "editovat" v seznamu organizací) Není-li u organizace délka
karantény explicitně uvedena, použije se jako defaultní hodnota číslo uvedené v business konstantě
DEFAULT_QUARANTINE_LENGTH.
114
Konfigurace
Běh CzechIdM je možné konfigurovat nastavením některých parametrů. Jejich nastavení lze provést v
konfiguračním souboru META-INF/idm_configuration.properties. V této sekci se podíváme
na význam jednotlivých parametrů.
13.1. Přehled konfiguračních parametrů
sso_use
Parametr sso_use udává, zda má být při
přihlašování uživatele do webového rozhraní
brán zřetel na případné jednotné přihlášení přes
SSO. Nabývá hodnot true a false. Je-li nastaven
na true, je při přihlašování nejprve hledán
parametr sso_uid v hlavičce HTTP požadavku.
sso_uid
Název parametru v hlavičce HTTP požadavku.
Slouží pro přihlašování pomocí SSO.
create_real_account_allowed
Zda mají být nové účty skutečně vytvářeny na
koncových systémech. Je-li nastaven na false,
jsou nově vytvořené účty pouze zapisovány
do souboru v adresáři uvedeném v parametru
fake_resources_dir.
update_real_account_allowed
Zda mají být nové účty skutečně aktualizovány
na koncových systémech. Je-li nastaven na
false, jsou aktualizace účtů pouze zapisovány
do souboru v adresáři uvedeném v parametru
fake_resources_dir.
delete_real_account_allowed
Zda mají být nové účty skutečně mazány
z koncových systémů. Je-li nastaven na
false, jsou mazané účty pouze zapisovány
do souboru v adresáři uvedeném v parametru
fake_resources_dir.
fake_resources_dir
Adresář, do něhož jsou zapisovány akce,
které by byly provedeny na koncovém
systému, je-li některý z parametrů
create_real_account_allowed,
update_real_account_allowed,
delete_real_account_allowed nastaven
na false.
auth_resource
Název koncového systému, vůči němuž má
být prováděna autentizace. Jedná se o název
systému z pohledu CzechIdM
auth_schema
Schéma na koncovém systému, vůči němuž má
být prováděna autentizace.
auth_id_attribute
Atribut obsahující identifikátor účtu na koncovém
systému, vůči němuž má být prováděna
autentizace.
115
Kapitola 13. Konfigurace
auth_also_with_repository
Atribut říkající, zda se při neúspěšném přihlášení
přes koncový systém má CzechIdM pokusit
uživatele přihlásit proti své repository.
Tabulka 13.1. Konfigurační parametry CzechIdM
Properties auth_resource, auth_schema a auth_id_attribute umožňují nastavit systém, vůči
němuž má při přihlašování probíhat autentizace. Pokud tyto properties nejsou nastaveny (nebo nejsou
nastaveny všechny), probíhá autentizace obvyklým způsobem vůči heši hesla v repository.
116
Webová služba
Účelem tohoto modulu je poskytování webové služby pro spouštění workflow v CzechIdM. Webová
služba poskytuje metody pro spouštění workflow dle specifikace systému CzechIdM. Název
spouštěného workflow a jeho parametry jsou těmto metodám předávány jako jejich parametry.
Webová služba umožňuje synchronní i asynchronní spuštění workflow. V případě synchronního
spuštění navrátí příslušná metoda odpovídající výstup. Metody implementované webovou službou
mohou spouštět pouze autentizovaní uživatelé s požadovaným oprávněním.
Prvním krokem je přihlášení klienta. Klient se musí prokázat svým uživatelským jménem a heslem.
Teprve přihlášený klient může spouštět workflow. Spustit workflow se však povede pouze těm
uživatelům, kteří mají pro tuto akci odpovídající oprávnění. Workflow může být spuštěno dvojím
způsobem, a to synchronně a asynchronně. Synchronně spuštěné workflow čeká na dokončení
prováděného kódu a následně vrací klientovi výstup. Oproti tomu asynchronní způsob na dokončení
workflow nečeká a klienta pouze informuje o případných chybách vzniklých během spuštění workflow.
14.1. Návrhový diagram tříd
Stěžejní třídou je třída WFLauncherBean. Jedná se o EJB stateless session beanu, která je zároveň
anotována jako webová služba. Tato třída implementuje rozhraní WFLauncherSEI, což je koncové
rozhraní dané webové služby, ve kterém jsou deklarovány metody webové služby. Zde konkrétně se
jedná o následujících šest metod:
• login – metoda k přihlašování klientů k webové službě
• logout – metoda k odhlašování klientů
• launchWorkflowAsynchronously – metoda pro asynchronní spouštění workflow
• launchWorkflowSynchronously – metoda pro synchronní spouštění workflow.
• launchWorkflowAsynchronouslyStringVars – alterntivní metoda pro asynchronní spouštění workflow
• launchWorkflowSynchronouslyStringVars – alterntivní metoda pro synchronní spouštění workflow
14.1.1. Metoda login
Metodě jsou předány jako parametry uživatelské jméno a heslo klienta. Pomocí instance třídy
Identity se získá instance třídy Credentials, ve které se nastaví předávané uživatelské jméno a
heslo. Dále je potřeba určit, že se klient přihlašuje prostřednictvím webové služby, aby se serverová
aplikace nepokoušela po úspěšném přihlášení zobrazit klientovi úvodní WWW obrazovku. Nyní se již
na instanci třídy Identity zavolá metoda login, která již provede přihlášení. O úspěšnosti přihlášení
je klient informován v návratové hodnotě.
14.1.2. Metoda logout
Tato metoda nemá žádné parametry. Po jejím zavolání je nad instancí třídy Identity zavolána
metoda logout, která provede odhlášení klienta. O úspěšnosti odhlášení je klient informován v
návratové hodnotě této metody.
117
Kapitola 14. Webová služba
14.1.3. Metoda launchWorkflowAsynchronously
Parametry této metody jsou název workflow, který má být spuštěn, a jeho případné parametry. Název
je metodě předán jako klasický řetězec. Parametrem pro workflow může být libovolný objekt (potomek
třídy java.lang.Object). Třída java.lang.Object však nemůže být uvedena jako atribut webové metody,
protože to není datový typ podporovaný JAXB. Tento problém je řešen tím způsobem, že se použije
uživatelsky definovaná třída InputWS. Tato třída transformuje libovolné objekty do bajtového pole a
naopak, přičemž bajtové pole je již podporovaným typem JAXB.
Prvním krokem metody je kontrola, zda je klient přihlášen. To se provádí prostřednictvím instance
třídy Identity. Následně se kontroluje, zda má přihlášený klient oprávnění pro spouštění workflow.
Pokud požadované oprávnění klient má, tak se spustí požadované workflow a případně se mu předají
parametry (zrekonstruované z instance třídy InputWS). Jelikož se workflow spouští v této metodě
asynchronně, tak metoda skončí, případně předá klientovi prostřednictvím instance třídy OutputWS
jako návratovou hodnotu libovolný objekt. Třída OutputWS provádí opět transformace mezi objekty a
bajtovým polem, ale na rozdíl od třídy InputWS zapouzdřuje dvě členské proměnné, a to standardní
výstup stdOut a chybový výstup errOut.
14.1.4. Metoda launchWorkflowSynchronously
Provádění této metody je velmi podobné provádění předchozí metody. Rozdílem zde je hlavně to,
že se workflow spouští synchronně. To znamená, že se čeká na jeho dokončení a výstup (ať již
standardní, tak i chybový) se předá klientovi opět prostřednictvím instance třídy OutputWS.
14.1.5. Metoda launchWorkflowAsynchronouslyStringVars
Tato metoda je velmi podobná metodě launchWorkflowAsynchronously. Liší se pouze ve způusobu
předávání parametrů. Tato metoda totiž nepřijímá parametry v podobě instance třídy OutputWS, ale
jako obyčejný String. V něm funkce očekává parametry pro workflow uložené v podobě XML. Funkce
tento XML String rozparsuje a spustí workflow se správnými parametry. Podoba XML je přesně
daná a je potřeba ji dodržet. Každý parametr je reprezentován jedním tagem. Název tagu je název
parametru a uvnitř něj je hodnota proměnné (typu String). Dohromady jsou pak parametry obaleny
tagem <root></root>. Skrze tuto funkci tedy narozdíl od launchWorkflowAsynchronously nelze poslat
jakýkoliv Objekt, ale pouze String. Jiné datové typy je potřeba přeložit na String (na straně klienta)
a zpět ve workflow, které o tom musí vědět. Smyslem této alternativní metody je umožnit snadnou
komunikaci s webovou službou i klientům napsaným v jiném jazyce než java, kteří nemohou vytvořit
instanci třídy InputWS.
<root>
<userName>FrantaWindows</userName>
<resource>VFN AD</resource>
<password>noveHeslo</password>
<changeInIdM>true</changeInIdM>
</root>
Příklad 14.1. Příklad správné podoby druhého parametru (typ String)
14.1.6. Metoda launchWorkflowSynchronouslyStringVars
Synchronní verze předchozí metody. Rozdíl je analogicky stejný jako mezi
launchWorkflowAsynchronously a launchWorkflowSynchronously.
118
Asynchronní volání metod JAX-WS
14.2. Asynchronní volání metod JAX-WS
JAX-WS podporuje asynchronní volání metod. To může být provedeno jak pro statický stub (statické
klienty), tak i za použití Dispatch API (dynamické proxy). Podporované jsou oba mechanismy
získávání návratových hodnot (polling i callback). V případě polling přístupu klient zavolá na serveru
asynchronní metodu a server klientovi ihned vrátí tzv. zástupný objekt, přičemž server dále vykonává
volanou metodu. Klient se prostřednictvím zástupného objektu dotazuje, zda již server poslal
návratovou hodnotu, kterou si poté prostřednictvím tohoto objektu vyzvedne. Vzorový kód pro „polling“
klienta je uveden níže.
CreditRatingService svc = ...;
Response<Score> response = svc.getCreditScoreAsync(customerFred);
while (!response.isDone()) {
// do something while we wait
}
// no cast needed, thanks to generics
Score score = response.get();
Příklad 14.2. polling klienta
Druhým mechanismem je callback přístup. Zde klient poskytuje handler pro příjetí a následné
zpracování návratové hodnoty. Callback mechanismus tedy vyžaduje dodatečné vstup v podobě
implementace daného handleru. Tuto implementaci má na starost programátor klientské aplikace.
Vzorový kód zahrnující zavolání webové metody a implementaci handleru je uveden níže.
CreditRatingService svc = ...;
Future<?> invocation = svc.getCreditScoreAsync(customerFred,
new AsyncHandler<Score>() {
public void handleResponse (
Response<Score> response)
{
Score score = response.get();
// do work here...
}
}
);
while(!invocation.isDone()){
// do something while we wait
}
Příklad 14.3. Volání webové metody a implementace handleru
14.3. Zamezení logování WARN [StatelessBeanContext]
EJBTHREE-1337
Při volání webových metod se do logu na serveru zapisuje následující varování:
119
Kapitola 14. Webová služba
WARN [StatelessBeanContext] EJBTHREE-1337: do not get WebServiceContext property from
stateless bean context, it should already have been injected
Jedná se o interní chybu aplikačního serveru JBoss. Jde o to, že JBossWS používá zastaralé API,
které bylo označeno jako deprecated. Z hlediska koncového vývojáře se nejedná o žádný problém,
vše pracuje tak, jak má. Nepříjemností je hlavně to, že toto varování zvyšuje velikost logu, což
je nepříjemné a znesnadňuje to jeho případný debugging. Zabránění výpisu tohoto varování je
jednoduché (stejně jako u jakéhokoliv jiného). Stačí v souboru $JBOSS_HOME/server/default/conf/
jboss-log4j.xml provést následující změnu.
<!-- Pro tridu StatelessBeanContext logovat az uroven ERROR -->
<category
name="org.jboss.ejb3.stateless.StatelessBeanContext">
<priority value="ERROR" />
</category>
Pokud je použita jiná konfigurace než defaultní, je samozřejmě potřeba náležitě upravit cestu ke
konfiguračnímu XML souboru.
120
Password filter
Password filter neboli filtr hesel je DLL knihovna pro Windows, která umožňuje implementovat
libovolnou politiku měnění hesel na operačních systémech Microsoft Windows. Při požadavku na
změnu hesla operační systém postupně zavolá všechny nainstalované password filtery (může jich být
více) s požadavkem na změnu hesla. Password filter podle politiky, kterou implementuje, rozhodne,
jestli změnu schválí nebo ne. Pokud je změna hesla schválena, operační systém změní heslo a znovu
zavolá password filter s potvrzením, že došlo ke změněně.
My používáme password filter typicky na MS Active Directory pro ověření hesla politikou definovanou
v CzechIdM, které password filter zavolá z MSAD prostřednictvím webové služby a následně pro
potvrzení změny, po kterém CzechIdM změní hesla daného uživatele ve všech koncových systémech
na něj napojených, čímž je realizována synchronizace hesel.
Proces synchronizace hesel po krocích:
1. Windows posílá požadavek na změnu hesla do CzechIdM.
2. CzechIdM ověří heslo podle svojí politiky hesel a pošle Windows odpověď.
3. Ve Windows se mění heslo.
4. Windows posílá CzechIdM informaci, že heslo bylo úspěšně změněno.
5. CzechIdM mění hesla ve všech koncových systémech.
15.1. Instalace password filteru na Windows
1. Zkopírujte PasswordFilterCzechIdM.dll a adresář PasswordFilterCzechIdM do systémového
adresáře. Při standardní instalaci je to C:/Windows/System32.
2. Otevřete editor registrů (regedit.exe) a najděte klíč HKEY_LOCAL_MACHINE\SYSTEM
\CurrentControlSet\Control\Lsa. Otevřete jeho multi-string value “Notification Packages” a doplňte
do ní PasswordFilterCzechIdM. (bez koncovky .dll) Stávající hodnoty nemažte.
3. Najděte a otevřete Local Security Policy. (např. Control panel (-> Performance and Maintenance) > Administrative Tools (-> Local Security Policy) ) V Account Policies -> Password Policy nastavte
položku “Password must meet complexity requirements” na Enabled.
4. Restartujte systém.
15.2. Konfigurace password filteru
Adresář PasswordFilterCzechIdM je úložiště pro konfigurační soubor PasswordFilterCzechIdM.ini,
SSL certifikát v PEM formátu a logovací soubor FilterLog.txt.
Název atributu
Popis
url
Cílová adresa, na které běží webová služba CzechIdM.
cert
Cesta k SSL certifikátu pro autentizaci serveru.
checkWorkflow
Název workflow v CzechIdM pro kontrolu politiky hesel.
changeWorkflow
Název workflow v CzechIdM pro změnu hesel na koncových systémech.
121
Kapitola 15. Password filter
Název atributu
Popis
resource
Identifikátor koncového systému. Nepovinný údaj. CzechIdM s ním může
naložit jak chce, například vynechat tento koncový systém ze seznamu
systmů, ve kterých změní heslo.
changeInIdM
Přepínač určující, jestli se má heslo změnit i v CzechIdM. Hodnoty true/
false.
loginName
Přihlašovací jméno uživatele CzechIdM s oprávněním měnit hesla
ostatním uživatelům (admin).
loginPassword
Heslo uživatele loginName pro přihlášení do CzechIdM přes webovou
službu.
sslSkipHostCheck
Přepínač určující, jestli se má přeskočit kontrola SSL certifikátu serveru
poskytujícího webovou službu proti doménovému jménu, pod kterým běží.
Tato možnost existuje pro testování protokolu https na localhostu. Hodnoty
true/false.
Tabulka 15.1. Atributy nastavitelné v konfiguračním souboru
15.3. Vytvoření password filteru
password filter je DLL knihovna napsaná v jazyce C++. K dispozici máme projekt pro Microsoft Visual
Studio 2010, ve kterém jsou naimplementované potřebné funkce včetně knihoven pro web service
komunikaci a SSL. Projekt je připraven k buildu, je však třeba dát pozor na konflikt mezi 32 a 64
bitovým systémem a přeložit projekt pro příslušnou platformu.
15.4. Komunikace password filteru s CzechIdM přes
webovou službu
Password filter funguje jako klient webové služby. Server je CzechIdM.
Ke komunikaci s webovou službou password filter použvá opensource C++ kihovnu gSOAP http://
gsoap2.sourceforge.net/. Tato knihovna je používána pod licencí GNU GPL v2, což znamená, že
výsledný software musí být opensource a volně distribuovatelný a modifikovatelný. (toto se týká pouze
password filteru, ne CzechIdM)
Zdrojové kódy funkcí obstarávajících komunikaci s webovou službou jsou vygenerovány z WSDL
souboru popisujícího webovou službu CzechIdM pomocí utilit wsdl2h a soapcpp2, které jsou také
součástí gSOAP. Za předpokladu, že se nebude měnit webová služba CzechIdM (nebo alespoň část
využívaná password filterem) nebude třeba tento krok opakovat.
Kdyby to přece jen potřeba bylo, zde je návod pro windows:
1. Vytvořte si pracovní adresář a zkopírujte do něj soubory wsdl2h.exe, soapcpp2.exe a WSDL
popisovač webové služby wsdl.wsdl. wsdl2h.exe a soapcpp2.exe najdete buť v adresáři projektu
pod gSoap/bin, nebo si je můžete stáhnout z http://gsoap2.sourceforge.net/
2. V příkazové řádce (cmd.exe) přejděte do pracovího adresáře a spusťte přkazy:
a. wsdl2h.exe -o wsdl.h wsdl.wsdl
b. soapcpp.exe -IC:\gSoap\gsoap-2.8\gsoap\import wsdl.h
3. Vygenerované soubory zkopírujte do domovského adresáře projektu password filteru.
122
Synchronizace hesel na straně CzechIdM
4. V hlavičkovém souboru stdsoap2.h doplňte řádek “#define WITH_COOKIES”,pokud tam není.
5. V hlavičkovém souboru stdsoap2.h doplňte řádek “#define WITH_OPENSSL”,pokud tam není.
Vygenerované zdrojové kódy jsou následně využívány v projektu password filteru. Vygenerované
funkce v nich se odkazují na knihovny z balíčku gSOAP, které je proto potřeba mít k dispozici pro build
projektu. (jsou součástí projektu)
15.5. Synchronizace hesel na straně CzechIdM
Na straně CzechIdM zajišťují proces synchronizace hesel 2 workflow: ws.password.check a
ws.password.change. ws.password.check pouze kontroluje, zda je změna hesla v souladu s politikou
hesel, ale nic nemění. Naproti tomu ws.password.change také provede kontrolu politiky a poté i
samotnou změnu hesel ve všech koncových systémech.
Obě workflow přijímají stejné vstupní argumenty:
• userName – název uživatelského účtu ve Windows (obecně jiný než v CzechIdM!)
• password – nové heslo
• resource – identifikátor koncového systému Windows. Pokud nebudeme připojovat více domén k
jednomu IdM, tak se asi obejdeme bez jeho použití. Je tam pro jistotu.
• changeInIdM – true/false přepínač, jestli se má změnit heslo i v IdM
Pro rychlé nalezení identity podle userName z Windows používame extended atribut,
jehož název je pro větší flexibilitu uložen v BusinessConstants pod konstantou
WINDOWS_USERNAME_ATTRIBUTE_NAME.
Obě workflow vracejí jako výstupní hodnotu true nebo false, podle toho, zda kontrola respektive
změna hesla proběhla v pořádku, nebo ne.
Všechny proměnné jsou typu String. (včetně true/false, vstupní i výstupní)
15.6. Zabezpečení přes SSL
V projektu se využívá knihovna OpenSSL.
Autentizace: Server (CzechIdM) se musí autentizovat certifikátem, aby nemohlo dojít ke zfalšování
serveru a odeslání hesla falešnému serveru. Naopak klient (Windows) se autentizovat nemusí,
protože server neposílá žádné citlivé údaje a navíc přihlásit se do CzechIdM a změnit si heslo stejně
může uživatel odkudkoliv skrz webové rozhraní.
Na serveru (=CzechIdM) musí být uložen privátní šifrovací klíč. Úložiště může být například
$JBOSS_HOME/server/default/conf/ssl. Dále musí být povolen https konektor v konfiguračním
souboru $JBOSS_HOME/server/default/deploy/jbossweb.sar/server.xml, ve kterém musí být navíc
uvedena cesta ke zmíněnému úložišti a heslo k němu.
Příkazy pro vytvoření šifrovacích klíčů (v typickém případě není potřeba klíče vytvářet, protože je dodá
klient):
$ mkdir -p $JBOSS_HOME/server/default/conf/ssl
123
Kapitola 15. Password filter
$ $JAVA_HOME/bin/keytool -genkey -alias czechidm -keyalg RSA -keystore $JBOSS_HOME/server/
default/conf/ssl/czechidm.keystore
$ $JAVA_HOME/bin/keytool -export -alias czechidm -keystore $JBOSS_HOME/server/default/conf/
ssl/czechidm.keystore -file $JBOSS_HOME/server/default/conf/ssl/czechidm.cer
$ openssl x509 -inform der -in $JBOSS_HOME/server/default/conf/ssl/czechidm.cer -outform pem out $JBOSS_HOME/server/default/conf/ssl/czechidm.pem
Příklad 15.1. Vytvoření SSL klíčů
15.7. Rizika a bezpečnostní opatření
• Únik citlivých informací: Posílané heslo odchytí třetí osoba (falešný server). Opatření: https protokol
s nainstalovaným certifikátem.
• V systémovém adresáři Active Directory jsou uloženy přihlašovací údaje administrátorského účtu
CzechIdM, SSL certifikát a samotný password filter. Do systémového adresáře proto nesmí mít
přístup nepovolané osoby, které by mohly tyto data ukrást nebo zaměnit.
• Před ukončením programu smazat(přepsat) paměť obsahující heslo.
• Kompatibilita s verzí Windows. Vstupní paramtery (jméno, heslo) jsou typu PUNICODE_STRING,
který je definován v hlavičkových souborech Windows (např. C:\Program Files\Microsoft SDKs
\Windows\v7.0A\Include\LsaLookup.h) a ty by se správně měly includovat. Jenže se tlučou s
vygenerovanými headery gSoapu. Proto je typ PUNICODE_STRING natvrdo definován uvnitř filtru.
Neměl by to být problém, ale je lepší o tom vědět a mít tak možnost to dohledat.
• Zacyklení: Pokud by CzechIdM ve fázi změny hesel na koncových systémech změnilo heslo i na
MS AD, znovu se aktivuje password filter a může vzniknout nekonečný cyklus (pokud mu nezabrání
nějaká politika, což by měla). Opatření: AD se při posílání zprávy identifikuje, a CzechIdM ho při
měnění hesel vynechá.
15.8. Užitečné informace pro vývoj a testování
Vedle samotného Visual Studio projektu PasswordFilterCzechIdM jsou v adresáři czechidm/Ralization/
PasswordFilter ještě Visual Studio projekty gSoapTest a dllExecutor. gSoapTest je konzolová aplikace
pro testování komunikace mezi Windows a CzechIdM pomocí C++ knihovny gSoa. dllExecutor je
konzolová aplikace, která umí spouštět funkce z dll knihovny, čímž umožňuje testování filtru bez
neustálých reinstalací (úprav registrů a restartů).
Když Windows volají password filter, vloží za uživatelské jméno jeden unicodový znak (nevím proč).
Ten my nechceme a proto password filter poslední znak uřezává. dllExecutor tohle ale nedělá a tak
je potřeba při jeho používání počítat se zkrácením zadaného uživatelského jména o 2 znaky. (převod
wchar->char)
gsoapTest: Funkcím gSoapu je možné zadat v parametru target místo url prázdný řetězec “”. gSoap
pak svůj dotaz místo odesílaní vypíše do konzole.
Nastavení project properties: Projekty gSoapTest a PasswordFilterCzechIdM musí mít v Configuration
Properties -> VC++ Directories -> Include directories nastavené adresáře obsahující zdrojové soubory
gSOAPu a statické knihovny OpenSSL. Statické knihovny OpenSSL ssleay32.lib a libeay32.lib je
nutné explicitně uvést v Linker->Input->Additional dependencies. Nakonec je zajímavá konvence
volání funkcí v C/C++ -> Advanced -> Calling convention. Jde o nastavení způsobu, jakým si funkce
mezi sebou předávají parametry a výstupní hodnoty. (pořadí parametrů, místo uložení zásobník/
124
Užitečné informace pro vývoj a testování
registry atd.) Exportované funkce DLL knihovny používají konvenci __stdcall (/Gz), ta ale není
kompatibilní s funkcemi ve statických knihovnách OpenSSL, což způsobí chybu při linkování. Proto
je potřeba nastavit Calling convention na __cdecl(/Gd). Pak se vnitřní funkce správně přeloží podle
__cdecl a exportované podle __stdcall (__stdcall v kódu přepisuje implicitní Calling convention).
125
126
Testování
16.1. Testování kódu
CzechIdM je testováno pomocí Unit (jednotkových) testů. Jsou to testy, které testují určitou část kódu
(např. metodu), nikoli funkcionalitu.
Testy jsou umístěny ve zvláštním projektu. Pro testování je použit framework TestNG (více na
www.testng.org), pro analýzu pokrytí testy potom nástroj Eclemma (více na www.eclemma.org), který
lze instalovat do Eclipse IDE. Testy se mohou spouštět buď pro každou testovací třídu zvlášť, nebo
se spustí pro všechny testovací třídy najednou. Třídy, které se mají být otestovány, jsou uvedené v
konfiguračním souboru testng.xml.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Suite" parallel="none">
<test name="All" preserve-order="false">
<classes>
<class name="JmenoTridy1Test"/>
<class name="JmenoTridyXTest"/>
</classes>
</test>
</suite>
Příklad 16.1. Soubor testng.xml
Mezi tagy <classes> jsou uvedeny jednotlivé třídy, které definují test. Třídy, které nejsou obsaženy
v testng.xml, nebudou otestovány, pře V OrganisationManagementBeanTest je parametr
alwaysRun použit, aby se naše vytvořená organizace vždy smazala. Zabráníme tím "zašpinění"
databáze daty z předchozích neprošlých testů, která by mohla ovlivnit testy následující.
stože se nachází v projektu. Atribut preserve-order určuje, zda je při testování nutné zachovat
pořadí testů tak, jak jsou uvedeny v seznamu classes, anebo může být pořadí testů náhodné.
Součástí projektů CzechIdM je sada testovacích tříd, které testují jak beany, tak statické metody tříd
z IdM. Jsou napsány testy například na OrganisationManagamentBean, RuleManagamentBean,
třídu PolicyUtils či jsou otestovány třídy pro zobrazení stránky, které se volají z workflow.
Obrázek 16.1. Pokrytí CzechIdm testy
Jak začít testovat:
• Nejprve musíme zvážit, které metody kterých tříd chceme otestovat.
127
Kapitola 16. Testování
• Poté musíme napsat testovací třídu, do ní testovací metody a samotné testy obsahující příkaz
assert.
• Nakonec spustíme test
16.2. Jak napsat jednoduchý test
Pro vytvoření jednoduchého testu stačí vytvořit v testovacím projektu třídu a do ní testovací metody,
které mají anotaci @Test. Tyto metody pak testují správné chování testované metody pomocí
jednoduchých příkazů assert (například můžeme testovat správnou výstupní hodnotu). Anotace
@Test může mít několik parametrů. S jejich pomocí můžeme testovací metody dělit do skupin,
vynechávat metody z testování, určovat pořadí, v jakém se provedou či reagovat na výjimky. Třídu
bychom neměli zapomenout vložit do konfiguračního souboru testng.xml.
public class PolicyUtilTest {
/**
* Otestuje, že text neobsahuje větší počet písmen, než bylo zadáno.
*/
@Test
public void checkMaxAlpha() {
Policy policy = new Policy();
policy.setMaxAlpha(3);
Assert.assertTrue(PolicyUtil.isTextValid("58_sd", policy, new Identity(), new
ArrayList<byte[]>()));
Assert.assertTrue(PolicyUtil.isTextValid("čD", policy, new Identity(), new
ArrayList<byte[]>()));
Assert.assertTrue(PolicyUtil.isTextValid("3č67979 . § á", policy, new Identity(), new
ArrayList<byte[]>()));
Assert.assertFalse(PolicyUtil.isTextValid(".:fEa664s", policy, new Identity(), new
ArrayList<byte[]>()));
}
/**
* Otestuje správný počet písmen.
*/
@Test
public void getNumberOfAlphaTest() {
Assert.assertEquals(PolicyUtil.getNumberOfAlpha("abc"), 3);
Assert.assertEquals(PolicyUtil.getNumberOfAlpha("a5B8c"), 3);
Assert.assertEquals(PolicyUtil.getNumberOfAlpha("2čžýŽ"), 4);
Assert.assertEquals(PolicyUtil.getNumberOfAlpha("0156 4_-)(§"), 0);
Assert.assertEquals(PolicyUtil.getNumberOfAlpha("01"), 0);
}
}
Příklad 16.2. Dvě testovací metody z PolicyUtilTest
Na příkladu je vidět, jak jednoduše otestovat metody z PolicyUtil a to pomocí metod assert z
TestNG. Metod pro testování existuje více a to například assertEquals, která testuje rovnost obou
parametrů, assertTrue testuje, zda je výraz roven true či assertNull testuje, zda je objekt roven
null. Pokud všechny assert příkazy v testovací metodě projdou, metoda úspěšně prošla testem.
Pokud některý z nich neprojde, metoda v testu neobstála.
128
Práce s výjimkami
16.3. Práce s výjimkami
V jistých situacích chceme testovat, zda nám testovaná metoda vyhazující výjimku tuto výjimku za
dané situace opravdu vyhodí. K anotaci @Test přidáme parametr expectedExceptions, v němž
uvedeme třídu očekávané výjimky.
public class PolicyUtils {
public static void validatePolicy(PolicyView a, PolicyView b) {
Integer minValue = null;
Integer maxValue = null;
String nameA = (String) a.get(PolicyViewHandler.NAME_ATTRIBUTE);
String nameB = (String) b.get(PolicyViewHandler.NAME_ATTRIBUTE);
minValue = (Integer) a.get(PolicyViewHandler.MIN_ALPHA_ATTRIBUTE);
maxValue = (Integer) a.get(PolicyViewHandler.MAX_ALPHA_ATTRIBUTE);
validate(minValue, maxValue, nameA, nameB);
}
private static void validate(Integer min, Integer max, String nameA, String nameB) {
if (min == null || max == null) {
return;
}
if (min > max) {
throw new IllegalArgumentException(String.format("Could not make intersection from
policies: %s and %s", nameA, nameB));
}
}
}
Příklad 16.3. Metoda ze třídy PolicyUtils v jisté situaci skončí výjimkou
public class PolicyUtilsTest {
@Test(expectedExceptions = IllegalArgumentException.class)
public void validatePolicyTest() {
PolicyView a = new PolicyView();
PolicyView b = new PolicyView();
a.put(PolicyViewHandler.NAME_ATTRIBUTE , "Nazev1");
b.put(PolicyViewHandler.NAME_ATTRIBUTE , "Nazev2");
a.put(PolicyViewHandler.MIN_ALPHA_ATTRIBUTE, new Integer(1));
a.put(PolicyViewHandler.MAX_ALPHA_ATTRIBUTE, new Integer(10));
a.put(PolicyViewHandler.MIN_LENGTH_ATTRIBUTE, new Integer(2));
a.put(PolicyViewHandler.MAX_LENGTH_ATTRIBUTE, new Integer(3));
a.put(PolicyViewHandler.MIN_LOWERCASE_ATTRIBUTE, new Integer(8));
a.put(PolicyViewHandler.MAX_LOWERCASE_ATTRIBUTE, new Integer(5));
a.put(PolicyViewHandler.MIN_NUMERIC_ATTRIBUTE, new Integer(2));
a.put(PolicyViewHandler.MAX_NUMERIC_ATTRIBUTE, new Integer(6));
a.put(PolicyViewHandler.MIN_SPECIAL_ATTRIBUTE, new Integer(3));
a.put(PolicyViewHandler.MAX_SPECIAL_ATTRIBUTE, new Integer(7));
129
Kapitola 16. Testování
a.put(PolicyViewHandler.MIN_UPPERCASE_ATTRIBUTE, new Integer(1));
a.put(PolicyViewHandler.MAX_UPPERCASE_ATTRIBUTE, new Integer(8));
PolicyUtils.validatePolicy(a, b);
}
}
Příklad 16.4. Testovací třída PolicyUtilsTest pro třídu PolicyUtils obsahuje metodu
validatePolicyTest, která očekává výjimku IllegalArgumentException.
Metoda validate vyhazuje výjimku v případě, že je min větší než max. Podíváme-li se
na naši testovací třídu a na její metodu validatePolicyTest, vidíme, že testuje metodu
validatePolicy z PolicyUtils. V určitou chvíli tedy může dojít k výjimce a to se stane ve chvíli,
kdy minimální hodnotě přiřadíme číslo větší, než je hodnota maximální. Pro účel testu zadáme právě
tyto parametry. Nakonec je zapotřebí přidat do anotace @Test parametr expectedExceptions,
v němž uvedeme naši očekávanou výjimku. V našem případě IllegalArgumentException.
Kdybychom očekávanou výjimku neuvedli, test by neprošel.
16.4. Když záleží na pořadí
V jistých situacích může být výhodné, aby se testovací metody spustily v pevně daném pořadí.
Mějme například testovací metodu A, testovací metodu B a testovací metodu C. Předpokládejme,
že potřebujeme, aby se testovací metoda B vždy spustila, až skončí testovací metoda A, a aby
se spustila testovací metoda C až v okamžiku, kdy skončí testovací metody A a B. K tomu nám
slouží parametr dependsOnMethods u anotace @Test, pomocí něhož specifikujeme, na kterých
předchozích testech konkrétní test závisí. Metody závislé na pořadí často využijeme u testování
takzvaných CRUD ("Create-Retrieve-Update-Delete") operací. Je zjevné, že testovat úspěšné
smazání objektu má smysl až poté, co byl objekt úspěšně vytvořen.
public class OrganisationManagementBeanTest {
@Test
public void organisationSimpleCreateAndRead() throws Exception {
//Kód testování vytvořené nové organizace
//a nastavení potřebných parametrů.
}
@Test(dependsOnMethods = {"organisationSimpleCreateAndRead"})
public void organisationSimpleUpdate() throws Exception {
//Kód testování updatu organizace.
}
@Test(dependsOnMethods = {"organisationSimpleUpdate"}, alwaysRun = true)
public void organisationSimpleDelete() throws Exception {
//Kód testování smazání organizace.
}
}
Příklad 16.5. Testovací třída OrganisationManagementBeanTest testuje CRUD operace.
Ve třídě OrganisationManagementBeanTest se nacházejí tři metody, které testují CRUD operace.
Potřebujeme, aby se nejdříve vytvořila organizace, abychom ji mohli později upravovat a nakonec
130
Psaní testů EJB session bean
smazat. Povšimněme si druhého parametru alwaysRun, který můžeme nastavit na true nebo
false. Hodnotou true říkáme, že pokud nějaká metoda závisí na metodě, která v testu neobstála,
bude se přesto pokračovat v testování. Defaultně je tento parametr nastaven na false. Pokud tedy
metoda A, na které testovaná metoda B závisí, testem neprojde, nebude se metoda B testovat. V
OrganisationManagementBeanTest je parametr alwaysRun použit, aby se naše vytvořená
organizace vždy smazala. Zabráníme tím "zašpinění" databáze daty z předchozích neprošlých testů,
která by mohla ovlivnit testy následující.
16.5. Psaní testů EJB session bean
Beany se testují specifickým způsobem.
Testovací třídu je třeba vytvořit jako potomka třídy SeamTest. Testovací metoda v sobě má příkaz
new ComponentTest(), ve kterém je implementován samotný test. Reference na EJB interface je
získávána pomocí třídy Component.
@Stateless
@Name("UserEJB")
public class UserEJBBean implements UserEJB {
@PersistenceContext
private EntityManager em;
public boolean insert(String firstname, String lastname) {
System.out.println("insert ...");
try {
User user = new User(firstname, lastname, 50000);
em.persist(user);
return true;
} catch (Exception e) {
log.error("Error - save to DB: " + e);
return false;
}
}
}
Příklad 16.6. EJB, která se bude testovat.
public class UserEJBTest extends SeamTest {
@Test
public void test_insert() throws Exception {
new ComponentTest() {
@Override
protected void testComponents() throws Exception {
UserEJB dao = (UserEJB) Component.getInstance(UserEJBBean.class);
boolean result = dao.insert("Jan", "Novak");
assertEquals(true, result);
}
}.run();
}
}
Příklad 16.7. Testovací třída.
131
Kapitola 16. Testování
16.6. Psaní testů Seam bean
@Name("testSeamBean1")
public class SeamTestBeanWithAnotation {
private Integer b = 1;
public String printHello(){
System.out.println("Hello Seam Bean from component with anotation!");
return null;
}
public Integer add(int c){
return b + c;
}
public Integer getB(){
return b;
}
public void setB(Integer b){
this.b = b;
}
}
Příklad 16.8. Seam bean, která se bude testovat.
@Test
public void test_beanWithAnotation() throws Exception {
new FacesRequest("/userEJB.xhtml") {
@Override
protected void invokeApplication() {
setValue("#{testSeamBean1.b}", new Integer(22));
Integer result = (Integer) invokeMethod("#{testSeamBean1.getB()}");
assertEquals(22, result.intValue());
SeamTestBeanWithAnotation seamTestBean = (SeamTestBeanWithAnotation)
Component.getInstance(SeamTestBeanWithAnotation.class);
assertEquals(new Integer(22), seamTestBean.getB());
}
}.run();
}
Příklad 16.9. Testovací metoda.
Na začátku je ukázka, jak lze nastavit hodnotu do proměnné. Následuje zavolání metody. Nakonec je
možné získat referenci na beanu a dále s ní pracovat.
16.7. Jak testovat workflow
CzechIdM obsahuje několik testovacích metod, které testují jednoduchá workflow. Tato worflow mohou
obsahovat ActionHandler třídy, např. metodu ShowPageAction, které chceme otestovat.
132
Pokrytí testy
@Test
public void workflowShowPageTest1() throws Exception {
new ComponentTest() {
@Override
protected void testComponents() throws Exception {
InputStream input;
ProcessDefinition processDefinition;
ProcessInstance processInstance;
ContextInstance contextInstance;
Assert.assertTrue(TestUtils.login());
try {
input = new FileInputStream(WORKFLOW_SHOW_PAGE_TEST_1_PATH);
processDefinition = ProcessDefinition.parseXmlInputStream(input);
processInstance = new ProcessInstance(processDefinition);
contextInstance = processInstance.getContextInstance();
Token token = processInstance.getRootToken();
//Testuje, zda se nachází v počátečním uzlu.
Assert.assertEquals("start-state3", token.getNode().getName());
contextInstance.setVariable("userName", USER_NAME_TEST);
processInstance.signal();
//Testuje správně nastavenou proměnnou userName, zda View není prázdné a zda je ve
stavu showPage
Assert.assertEquals("admin", contextInstance.getVariable("userName"));
Assert.assertNotNull(contextInstance.getVariable("userView"));
Assert.assertEquals("showPage", token.getNode().getName());
processInstance.signal();
//Testuje zda se nachází v koncovém uzlu
Assert.assertEquals("end-state1", token.getNode().getName());
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
TestUtils.logout();
}
}
}.run();
}
Příklad 16.10. Metoda testuje workflow.
Na začátku naší testovací metody musíme worflow načíst a pak manuálně přecházet mezi stavy a
testovat, zda se správně nastavily proměnné a zda jsme ve správném stavu.
16.8. Pokrytí testy
Při testování kódu je zapotřebí měřit mimo počet úspěšných testů také to, jaké je pokrytí testy.
Pokrytím testy rozumíme poměr mezi počtem řádků otestovaného a neotestovaného kódu.
Dobrým nástrojem pro toto měření je Eclemma, jehož prostřednictvím se spustí testování kódu.
Jakmile testy proběhnou, spustí nástroj detailní statistiku, z níž lze vyčíst, kolik čeho bylo otestováno a
133
Kapitola 16. Testování
jaké je celkové pokrytí. Nástroj nám také vyznačí, které části kódu byly otestovány a které ne. Zelenou
barvou se označí řádky, které jsou otestované, červenou jsou neotestované řádky a žlutou barvou jsou
řádky, které jsou otestované tak napůl. Například podmínky, kdy jen část je splněná.
Cílem je mít co nejvíce zelených řádek a tím tedy vyšší pokrytí testy.
Obrázek 16.2. Pokryté části kódu - vyznačeno zelenou barvou
Obrázek 16.3. Nepokryté části kódu - vyznačeno červenou barvou
134
Nástroje
17.1. IdM Uploader
IdM Uploader je jednoduchá Java aplikace, s jejíž pomocí může vývojář svá nově vytvořená nebo
pozměněná workflow, pravidla nebo e-mailové šablony nahrát do repository. S databází komunikuje
pomocí JDBC a obsluhuje tabulky "workflows_definitions", "rules_definitions" a "email_templates".
Po spuštění projde všechny adresáře na stanovené cestě a nahraje obsah jejich .xml souborů do
repository.
Cestu, na níž IdM Uploader hledá definice workflow, definice pravidel a e-mailové šablony, lze stanovit
v souboru conf.properties v adresáři eu.bcvsolutions.wfuploader. Kromě těchto cest je v souboru
možné definovat port, na kterém repository běží, host, databázi, uživatelské jméno a heslo pro přístup
a případné další parametry spojení.
Před načtením každého workflow, pravidla nebo e-mailové šablony je .xml souboru zpracován pomocí
parseru SAX.
Jelikož by workflow, pravidla a e-mailové šablony do repository takto vložené neměly coby entity
v CzechIdM přiřazen unikátní identifikátor entityId, který v CzechIdM běžně přiřazuje metoda
generateEntityIdAndSetOwnerIdToAttributes() na třídě IdmEntity, je entityId
generováno ve stejném formátu přímo uploaderem.
17.2. IdMKeyGenerator
IdMKeyGenerator je Java aplikace, které slouží ke generování klíčů pro šifrovaná spojení s koncovými
systémy. V současnosti je spojení zpravidla realizováno pomocí blokové šifry AES, klíčovou třídou je
proto třída AESKeyGenerator, která vytváří klíč pro AES. Kdyby bylo AES v budoucnu nahrazeno
jiným kryptografickým standardem, může být IdMKeyGenerator snadno upraven. Vygenerovaný klíč je
uložen buď do souboru uvedeného v prvním parametru při spuštění, anebo (není-li parametr uveden)
do souboru "keyAES".
17.3. JBPMSyntaxCheck
Jednoduchá Java aplikace sloužící k off-line kontrole syntaxe pravidel a workflow.
Před spuštěním je nutné nastavit dvě properties: path - cestu k adresáři, který má být zkontrolován,
a businessConstants - cestu k adresáři, ve kterém se nachází soubor s business konstantami getBusinessConstants.xml.
Aplikace po svém spuštění prochází všechny xml soubory v zadaném podstromě a hlásí:
• Chyby v xml, například neuzavřené tagy
• Chyby v syntaxi BeanShellu, například chybějící středníky, závorky a z hlediska gramatiky
nesmyslné konstrukce
• Chybějící importy - vychází z předpokladu, že třídy jsou pojmenovány s velkým písmenem na
začátku a nejsou složeny výhradně z velkých písmen (takové řetězce považuje za konstanty).
Jelikož některé třídy není potřeba importovat, protože jsou v balíku java.lang nebo java.util, jsou
tyto třídy přímo vyjmenovány jako konstanty ve třídě Main. Případné rozšíření seznamu těchto
obvyklých tříd je úkolem pro každého vývojáře CzechIdM.
135
Kapitola 17. Nástroje
• Volání neexistujících metod na známých třídách.
• Přístup k neexistujícím atributům na známých třídách.
• Nedeklarované konstanty.
• Nebezpečné zapisování do proměnných deklarovaných v BeanShellu uvnitř bloku.
JBPMSyntaxCheck ještě není hotový a nelze ho považovat za seriózní testovací nástroj. Jeho cílem
je pouze usnadnit vývoj programátorům, kteří chtějí syntaktickou chybu odhalit dřív než po deployi na
server. Vychází z myšlenky, že když si není chybou jistý, nic nehlásí a předpokládá svou vlastní chybu.
Hlásí-li tedy chybu, je chyba v kódu pravidla nebo workflow. Nehlásí-li chybu, je to dobrý začátek, ale
stále je možné, že pravidlo nebo workflow chybu obsahuje.
136
Příloha A. Revision History
Revize 0.0-1
Thu Nov 29 2012
Zdeněk Burda
[email protected]
Vytvoření nového formátu dokumentu a migrace ze starého.
137
138
Rejstřík
F
feedback
informace pro hlášení chyb tohoto dokumentu,
ix
139
140

Podobné dokumenty

Jak na CzechIdM - Úvod pro programátory systému CzechIdM

Jak na CzechIdM - Úvod pro programátory systému CzechIdM 6. Příklady obvyklých akcí 6.1. Získání atributů uživatele ............................................................................................ 6.2. Změna atributu uživatele ..................

Více

O soutěži Antivirový program avast! Free Antivirus 6

O soutěži Antivirový program avast! Free Antivirus 6 Použití produktu: Drobo B800i je samostatné externí úložiště dat s intuitivní obsluhou a bez nároků na znalosti diskových polí. Produkt je připojen pomocí rozhraní iSCSI a určen především pro použi...

Více