Bevezetés a tavaszi biztonsági ACL-be

1. Bemutatkozás

Beléptető lista (ACL) egy objektumhoz csatolt engedélyek listája. An ACL meghatározza, hogy mely azonosítók mely műveleteket kapnak egy adott objektumon.

Tavaszi biztonság Beléptető listavan a Tavaszi komponens, amely támogatja Domain Object Security. Egyszerűen fogalmazva, a Spring ACL segít meghatározni az egyes felhasználók / szerepkörök engedélyeit egyetlen tartomány objektumán - az egész hálózat helyett, a tipikus műveletenkénti szinten.

Például egy felhasználó a szerepkörrel Rendszergazda Láthatjuk (OLVAS) és szerkesztés (ÍR) összes üzenet a Központi értesítő doboz, de a normál felhasználó csak üzeneteket láthat, kapcsolódhat hozzájuk, és nem szerkesztheti. Eközben mások felhasználják a szerepet Szerkesztő láthat és szerkeszthet néhány konkrét üzenetet.

Ezért a különböző felhasználóknak / szerepköröknek minden egyes objektumhoz különböző engedélyei vannak. Ebben az esetben, Tavaszi ACL képes a feladat elérésére. Megvizsgáljuk, hogyan állíthatjuk be az alapvető engedélyellenőrzést Tavaszi ACL ebben a cikkben.

2. Konfiguráció

2.1. ACL adatbázis

Használni Tavaszi biztonsági ACL, négy kötelező táblát kell létrehoznunk az adatbázisunkban.

Az első táblázat az ACL_CLASS, amely a tartományobjektum osztálynevét tárolja, az oszlopok a következőket tartalmazzák:

  • ID
  • OSZTÁLY: a biztonságos domain objektumok osztályneve, például:com.baeldung.acl.persistence.entity.NoticeMessage

Másodszor, szükségünk van a ACL_SID táblázat, amely lehetővé teszi számunkra, hogy egyetemesen azonosítsuk a rendszer bármely elvét vagy tekintélyét. A táblázatnak szüksége van:

  • ID
  • SID: amely a felhasználónév vagy a szerep neve. SID áll Biztonsági identitás
  • FŐ: 0 vagy 1, jelezve, hogy a megfelelő SID egy megbízó (felhasználó, például mary, mike, jack…) vagy hatóság (szerep, például ROLE_ADMIN, ROLE_USER, ROLE_EDITOR…)

A következő táblázat az ACL_OBJECT_IDENTITY, amely információkat tárol minden egyedi tartományobjektumról:

  • ID
  • OBJECT_ID_CLASS: meghatározza a tartomány objektum osztályát,linkek ACL_CLASS asztal
  • OBJECT_ID_IDENTITY: A tartományi objektumok az osztálytól függően sok táblában tárolhatók. Ezért ez a mező tárolja a célobjektum elsődleges kulcsát
  • PARENT_OBJECT: adja meg ennek szülőjét Object Identity ezen a táblázaton belül
  • OWNER_SID: ID az objektum tulajdonosának linkje ACL_SID asztal
  • ENTRIES_INTERITTING: hogy ACL bejegyzések az objektum örököl a szülő objektumtól (ACL bejegyzések -ban vannak meghatározva ACL_ENTRY asztal)

Végül a ACL_ENTRY tárolja az egyes engedélyeket SID egy Object Identity:

  • ID
  • ACL_OBJECT_IDENTITY: adja meg az objektum azonosságát, a linkeket ACL_OBJECT_IDENTITY asztal
  • ACE_ORDER: a jelenlegi bejegyzés sorrendje a ACL bejegyzések a megfelelő listája Object Identity
  • SID: a célpont SID amelyekre az engedélyt megadják vagy elutasítják, linkek ACL_SID asztal
  • MASZK: az egész bites maszk, amely a tényleges engedélyt adja vagy megtagadja
  • MEGADÁS: az 1. érték megadás, érték 0 tagadást jelent
  • AUDIT_SIKER és AUDIT_FAILURE: ellenőrzés céljából

2.2. Függőség

Ahhoz, hogy használni tudja Tavaszi ACL projektünkben először határozzuk meg függőségeinket:

 org.springframework.security spring-security-acl org.springframework.security spring-security-config org.springframework spring-context-support net.sf.ehcache ehcache-core 2.6.11 

Tavaszi ACL tárolásához gyorsítótár szükséges Object Identity és ACL bejegyzések, ezért felhasználjuk Ehcache itt. És támogatni Ehcache ban ben Tavaszi, szükségünk van a tavasz-kontextus-támogatás.

Ha nem a Spring Boot programmal dolgozunk, akkor kifejezetten hozzá kell adnunk a verziókat. Ezeket a Maven Centralon ellenőrizhetjük: spring-security-acl, spring-security-config, spring-context-support, ehcache-core.

2.3. ACL-hez kapcsolódó konfiguráció

Engedélyezéssel biztosítanunk kell minden olyan módszert, amely biztonságos tartományi objektumokat ad vissza, vagy módosításokat hajt végre az objektumon Globális módszerbiztonság:

@Configuration @EnableGlobalMethodSecurity (prePostEnabled = true, securedEnabled = true) nyilvános osztály AclMethodSecurityConfiguration kiterjeszti a GlobalMethodSecurityConfiguration {@Autowired MethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler; @Orride védett MethodSecurityExpressionHandler createExpressionHandler () {return defaultMethodSecurityExpressionHandler; }}

Engedélyezzük is Kifejezés-alapú hozzáférés-vezérlés a beállítással prePostEnabled nak nek igaz használni Tavaszi kifejezés nyelve (SpEL). Ráadásul, szükségünk van egy kifejezéskezelőre ACL támogatás:

@Bean public MethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler () {DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler (); AclPermissionEvaluator licenseEvaluator = új AclPermissionEvaluator (aclService ()); kifejezésHandler.setPermissionEvaluator (licenseEvaluator); return kifejezésHandler; }

Ennélfogva, kijelöljük AclPermissionEvaluator hoz DefaultMethodSecurityExpressionHandler. Az értékelőnek szüksége van a MutableAclService az engedélybeállítások és a tartományobjektum-definíciók betöltéséhez az adatbázisból.

Az egyszerűség kedvéért a megadottakat használjuk JdbcMutableAclService:

@Bean public JdbcMutableAclService aclService () {return new JdbcMutableAclService (dataSource, lookupStrategy (), aclCache ()); }

Neveként a JdbcMutableAclService használ JDBCTemplate az adatbázis-hozzáférés egyszerűsítése érdekében. Szüksége van egy Adatforrás (mert JDBCTemplate), LookupStrategy (optimalizált keresést nyújt az adatbázis lekérdezésekor), és egy AclCache (gyorsítótár ACLBejegyzés és Object Identity).

Ismét az egyszerűség kedvéért használjuk a biztosítottakat BasicLookupStrategy és EhCacheBasedAclCache.

@Autowired DataSource dataSource; @Bean public AclAuthorizationStrategy aclAuthorizationStrategy () {return new AclAuthorizationStrategyImpl (new SimpleGrantedAuthority ("ROLE_ADMIN")); } @Bean public PermissionGrantingStrategy engedélyGrantingStrategy () {return new DefaultPermissionGrantingStrategy (új ConsoleAuditLogger ()); } @Bean public EhCacheBasedAclCache aclCache () {return new EhCacheBasedAclCache (aclEhCacheFactoryBean (). GetObject (), licenseGrantingStrategy (), aclAuthorizationStrategy ()); } @Bean public EhCacheFactoryBean aclEhCacheFactoryBean () {EhCacheFactoryBean ehCacheFactoryBean = new EhCacheFactoryBean (); ehCacheFactoryBean.setCacheManager (aclCacheManager (). getObject ()); ehCacheFactoryBean.setCacheName ("aclCache"); return ehCacheFactoryBean; } @Bean public EhCacheManagerFactoryBean aclCacheManager () {return new EhCacheManagerFactoryBean (); } @Bean public LookupStrategy lookupStrategy () {return new BasicLookupStrategy (dataSource, aclCache (), aclAuthorizationStrategy (), new ConsoleAuditLogger ()); } 

Itt a AclAuthorizationStrategy felelős annak megállapításáért, hogy a jelenlegi felhasználó rendelkezik-e minden objektumhoz szükséges engedéllyel, vagy sem.

Támogatásra szorul PermissionGrantingStrategy, amely meghatározza a logikát annak meghatározására, hogy engedélyt kapnak-e egy adott személyre SID.

3. Módszer biztonsága rugós ACL-lel

Eddig minden szükséges konfigurációt elvégeztünk. Most beírhatjuk a szükséges ellenőrzési szabályt a biztonságos módszereinkre.

Alapértelmezés szerint, Tavaszi ACL utal rá BasePermission osztály az összes rendelkezésre álló engedélyhez. Alapvetően van egy OLVASD, ÍRJ, LÉTREHOZ, TÖRLD és ADMINISZTRÁCIÓ engedély.

Próbálja meg meghatározni néhány biztonsági szabályt:

@PostFilter ("hasPermission (filterObject, 'READ')") List findAll (); @PostAuthorize ("hasPermission (returnObject, 'READ')") NoticeMessage findById (Egész id); @PreAuthorize ("hasPermission (#noticeMessage, 'WRITE')") NoticeMessage save (@Param ("noteMessage") NoticeMessage noticeMessage);

Végrehajtása után Találd meg mindet() módszer, @PostFilter kiváltásra kerül. A szükséges szabály hasPermission (filterObject, „READ”), csak azokat jelenti vissza NoticeMessage melyik jelenlegi felhasználó rendelkezik OLVAS engedély.

Hasonlóképpen, @PostAuthorize végrehajtása után vált ki findById () módszerrel, csak a NoticeMessage objektum, ha az aktuális felhasználó rendelkezik OLVAS engedélyt rá. Ha nem, akkor a rendszer dob egy AccessDeniedException.

A másik oldalon a rendszer kiváltja a @PreAuthorize megjegyzés, mielőtt a mentés() módszer. Eldönti, hogy a megfelelő módszer hol hajtható végre, vagy sem. Ha nem, AccessDeniedException dobni fogják.

4. Műveletben

Most ezeket a konfigurációkat teszteljük JUnit. Majd használjuk H2 adatbázis a lehető legegyszerűbb konfigurálás érdekében.

Ki kell egészítenünk:

 com.h2database h2 org.springframework tavasz-teszt 

4.1. A forgatókönyv

Ebben a forgatókönyvben két felhasználónk lesz (menedzser, hr) és egy felhasználói szerepkör (ROLE_EDITOR), tehát a mi acl_sid lesz:

INSERT INTO acl_sid (id, megbízó, sid) ÉRTÉKEK (1, 1, 'menedzser'), (2, 1, 'óra'), (3, 0, 'ROLE_EDITOR');

Aztán ki kell jelentenünk NoticeMessage osztályban acl_class. És három esetben NoticeMessage osztály beillesztésre kerül rendszer_üzenet.

Ezenkívül ennek a 3 példánynak a megfelelő rekordjait itt kell deklarálni acl_object_identity:

INSERT INTO acl_class (id, class) ÉRTÉKEK (1, 'com.baeldung.acl.persistence.entity.NoticeMessage'); INSERT INTO system_message (id, tartalom) ÉRTÉKEK (1, 'Első szintű üzenet'), (2, 'Második szintű üzenet'), (3, 'Harmadik szintű üzenet'); INSERT INTO acl_object_identity (id, object_id_class, object_id_identity, parent_object, tulajdonos_sid, bejegyzések_örökölt) ÉRTÉKEK (1, 1, 1, NULL, 3, 0), (2, 1, 2, NULL, 3, 0), (3, 1, 3, NULL, 3, 0);

Kezdetben megadjuk OLVAS és ÍR engedélyek az első objektumra (id = 1) a felhasználónak menedzser. Eközben bármelyik felhasználó ROLE_EDITOR lesz OLVAS engedély mindhárom tárgyra, de csak rendelkezik ÍR engedély a harmadik objektumra (id = 3). Emellett felhasználó óra csak lesz OLVAS engedély a második objektumra.

Itt, mert az alapértelmezettet használjuk Tavaszi ACLBasePermission osztály engedélyellenőrzéshez, a OLVAS engedély 1 lesz, a maszk értéke pedig ÍR engedély 2. lesz. Adataink acl_entry lesz:

INSERT INTO acl_entry (id, acl_object_identity, ace_order, sid, mask, engedélyezés, audit_siker, audit_failure) ÉRTÉKEK (1, 1, 1, 1, 1, 1, 1, 1), (2, 1, 2, 1, 2, 1, 1, 1), (3, 1, 3, 3, 1, 1, 1, 1), (4, 2, 1, 2, 1, 1, 1, 1), (5, 2, 2, 3, 1, 1, 1, 1), (6, 3, 1, 3, 1, 1, 1, 1), (7, 3, 2, 3, 2, 1, 1, 1);

4.2. Próbaper

Először megpróbáljuk felhívni a Találd meg mindet módszer.

Konfigurációnként a metódus csak azokat adja vissza NoticeMessage amelyen a felhasználó rendelkezik OLVAS engedély.

Ezért azt várjuk, hogy az eredménylista csak az első üzenetet tartalmazza:

@Test @WithMockUser (felhasználónév = "manager") public void givenUserManager_whenFindAllMessage_thenReturnFirstMessage () {Lista részletei = repo.findAll (); assertNotNull (részletek); assertEquals (1, részletek.méret ()); assertEquals (FIRST_MESSAGE_ID, részletek.get (0) .getId ()); }

Ezután megpróbáljuk ugyanezt a módszert meghívni minden olyan felhasználóval, akinek szerepe van - ROLE_EDITOR. Vegye figyelembe, hogy ebben az esetben ezek a felhasználók rendelkeznek a OLVAS engedély mindhárom tárgyra.

Ezért azt várjuk, hogy az eredménylista mindhárom üzenetet tartalmazza:

@Test @WithMockUser (szerepek = {"SZERKESZTŐ"}) public void givenRoleEditor_whenFindAllMessage_thenReturn3Message () {Lista részletei = repo.findAll (); assertNotNull (részletek); assertEquals (3, részletek.méret ()); }

Ezután a menedzser felhasználó, megpróbáljuk megszerezni az első üzenetet id alapján, és frissíteni a tartalmát - aminek minden rendben működnie kell:

@Test @WithMockUser (felhasználónév = "manager") public void givenUserManager_whenFind1stMessageByIdAndUpdateItsContent_thenOK () {NoticeMessage firstMessage = repo.findById (FIRST_MESSAGE_ID); assertNotNull (firstMessage); assertEquals (FIRST_MESSAGE_ID, firstMessage.getId ()); firstMessage.setContent (EDITTED_CONTENT); repo.save (firstMessage); NoticeMessage editedFirstMessage = repo.findById (FIRST_MESSAGE_ID); assertNotNull (editedFirstMessage); assertEquals (FIRST_MESSAGE_ID, editedFirstMessage.getId ()); assertEquals (EDITTED_CONTENT, editedFirstMessage.getContent ()); }

De ha van olyan felhasználó, akinek a ROLE_EDITOR szerepkör frissíti az első üzenet tartalmát - rendszerünk dob egy AccessDeniedException:

@Test (várható = AccessDeniedException.class) @WithMockUser (szerepek = {"SZERKESZTŐ"}) public void givenRoleEditor_whenFind1stMessageByIdAndUpdateContent_thenFail () {NoticeMessage firstMessage = repo.fIDById (FO assertNotNull (firstMessage); assertEquals (FIRST_MESSAGE_ID, firstMessage.getId ()); firstMessage.setContent (EDITTED_CONTENT); repo.save (firstMessage); }

Hasonlóképpen a óra a felhasználó azonosító szerint megtalálja a második üzenetet, de nem tudja frissíteni:

@Test @WithMockUser (felhasználónév = "hr") public void givenUsernameHr_whenFindMessageById2_thenOK () {NoticeMessage secondMessage = repo.findById (SECOND_MESSAGE_ID); assertNotNull (secondMessage); assertEquals (SECOND_MESSAGE_ID, secondMessage.getId ()); } @Test (várható = AccessDeniedException.class) @WithMockUser (felhasználónév = "hr") public void givenUsernameHr_whenUpdateMessageWithId2_thenFail () {NoticeMessage secondMessage = new NoticeMessage (); secondMessage.setId (SECOND_MESSAGE_ID); secondMessage.setContent (EDITTED_CONTENT); repo.save (secondMessage); }

5. Következtetés

Alapvető konfiguráción és használaton mentünk keresztül Tavaszi ACL ebben a cikkben.

Mint tudjuk, Tavaszi ACL szükséges speciális táblák az objektum, az elv / jogosultság és az engedélyek beállításához. Azokkal a táblákkal való minden interakciónak, különösen a frissítési műveletnek, át kell mennie AclService. Feltárjuk ezt a szolgáltatást az alapszinthez CRUD egy jövőbeli cikkben.

Alapértelmezés szerint korlátozva vagyunk előre definiált engedélyre a következőben: BasePermission osztály.

Végül ennek az oktatóanyagnak a megvalósítása megtalálható a Github oldalon.


$config[zx-auto] not found$config[zx-overlay] not found