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
.................................................................................... 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 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 či . Š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.
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')}">
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 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
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 . Takto namapovaná proměnná se poté přenese do šablony. Element 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 , 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. <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);
Příklad 4.4. Pomocí elementu 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 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"> <pageName>admin/user/view
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 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
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.
Příklad 4.7. Změna stavu workflow. Po kliknutí na tlačítko dojde ke spuštění přechodu 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.
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
<process-definition xmlns="urn:jbpm.org:jpdl-3.2"
name="disableUser">
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
<start-state name="start-state"> <node name="getUserView"> <node name="setUserDisabled"> <node name="checkinView"> <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);
34
Ukázkové workflow
Java instrukce jsme do uzlu vložili obalené tagy <event>, <script> a <expression>. Za povšimnutí stoji tagy 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 ; 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]);
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);
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}.
<emailTemplate xmlns="urn:jbpm.org:bcv_emailTemplate-1.0" name="UserRoleApprove"> cs <subject>Schválení přidání role uživateli #{userFullName} Dobrý den, žádáme Vás o schválení přidělení role "#{roleName}" uživateli "#{userName}". Popis role: #{roleDescription}
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
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:
Atribute "name" je důležitý, musí pravidlo jednoznačně identifikovat, přes toto jméno bude definice pravidla vyhledána. Dovnitř do tagu 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.
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;
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".
<description>
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
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
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 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 . 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.
<userName>FrantaWindows VFN AD <password>noveHeslo true
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.
<priority value="ERROR" />
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.
<suite name="Suite" parallel="none">
Příklad 16.1. Soubor testng.xml Mezi tagy 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())); Assert.assertTrue(PolicyUtil.isTextValid("čD", policy, new Identity(), new ArrayList())); Assert.assertTrue(PolicyUtil.isTextValid("3č67979 . § á", policy, new Identity(), new ArrayList())); Assert.assertFalse(PolicyUtil.isTextValid(".:fEa664s", policy, new Identity(), new ArrayList())); } /** * 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