Histoire de base et systématique Histoire de certification / autorisation Histoire Remember-Me Histoire CSRF Histoire de gestion de session L'histoire de l'en-tête de la réponse Histoire de la sécurité de la méthode Histoire CORS L'histoire de Run-As Test story Parlez de la coopération avec MVC et Boot
Édition supplémentaire Ce que Spring Security peut et ne peut pas faire
Le traitement des autorisations en utilisant hasAuthority ()
etc. est essentiellement contrôlé en unités de fonctions.
(Une certaine fonction (écran) doit avoir l'autorité de XX, etc.)
Cependant, lors de la création effective d'un système, il est rarement nécessaire de gérer les autorisations données par données. Par exemple, seules les personnes appartenant au même groupe que la personne qui a créé les données peuvent voir les données, ou seul le créateur ou l'administrateur système peut mettre à jour les données.
Spring Security fournit un mécanisme pour réaliser un tel contrôle d'accès sur une base de données par données.
Il est appelé sécurité des objets de domaine ou ACL (liste de contrôle d'accès).
Hello World
build.gradle
dependencies {
compile 'org.springframework.security:spring-security-web:4.2.1.RELEASE'
compile 'org.springframework.security:spring-security-config:4.2.1.RELEASE'
compile 'org.springframework.security:spring-security-acl:4.2.1.RELEASE'★ Ajout
compile 'org.springframework:spring-jdbc:4.3.7.RELEASE'
compile 'com.h2database:h2:1.4.193'
}
DB
src/main/resources/sql/create_acl_tables.sql
CREATE TABLE ACL_SID (
ID BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
PRINCIPAL BOOLEAN NOT NULL,
SID VARCHAR_IGNORECASE(100) NOT NULL,
CONSTRAINT UNIQUE_UK_1 UNIQUE(SID,PRINCIPAL)
);
CREATE TABLE ACL_CLASS(
ID BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
CLASS VARCHAR_IGNORECASE(100) NOT NULL,
CONSTRAINT UNIQUE_UK_2 UNIQUE(CLASS)
);
CREATE TABLE ACL_OBJECT_IDENTITY(
ID BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
OBJECT_ID_CLASS BIGINT NOT NULL,
OBJECT_ID_IDENTITY BIGINT NOT NULL,
PARENT_OBJECT BIGINT,
OWNER_SID BIGINT,
ENTRIES_INHERITING BOOLEAN NOT NULL,
CONSTRAINT UNIQUE_UK_3 UNIQUE(OBJECT_ID_CLASS, OBJECT_ID_IDENTITY),
CONSTRAINT FOREIGN_FK_1 FOREIGN KEY(PARENT_OBJECT)REFERENCES ACL_OBJECT_IDENTITY(ID),
CONSTRAINT FOREIGN_FK_2 FOREIGN KEY(OBJECT_ID_CLASS)REFERENCES ACL_CLASS(ID),
CONSTRAINT FOREIGN_FK_3 FOREIGN KEY(OWNER_SID)REFERENCES ACL_SID(ID)
);
CREATE TABLE ACL_ENTRY(
ID BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
ACL_OBJECT_IDENTITY BIGINT NOT NULL,
ACE_ORDER INT NOT NULL,
SID BIGINT NOT NULL,
MASK INTEGER NOT NULL,
GRANTING BOOLEAN NOT NULL,
AUDIT_SUCCESS BOOLEAN NOT NULL,
AUDIT_FAILURE BOOLEAN NOT NULL,
CONSTRAINT UNIQUE_UK_4 UNIQUE(ACL_OBJECT_IDENTITY, ACE_ORDER),
CONSTRAINT FOREIGN_FK_4 FOREIGN KEY(ACL_OBJECT_IDENTITY) REFERENCES ACL_OBJECT_IDENTITY(ID),
CONSTRAINT FOREIGN_FK_5 FOREIGN KEY(SID) REFERENCES ACL_SID(ID)
);
src/main/resources/sql/insert_acl_tables.sql
INSERT INTO ACL_CLASS (ID, CLASS)
VALUES (100, 'sample.spring.security.domain.Foo');
INSERT INTO ACL_SID (ID, PRINCIPAL, SID)
VALUES (9, true, 'hoge');
INSERT INTO ACL_SID (ID, PRINCIPAL, SID)
VALUES (99, false, 'SAMPLE_AUTHORITY');
INSERT INTO ACL_OBJECT_IDENTITY (ID, OBJECT_ID_CLASS, OBJECT_ID_IDENTITY, PARENT_OBJECT, OWNER_SID, ENTRIES_INHERITING)
VALUES (1000, 100, 44, NULL, 9, true);
INSERT INTO ACL_ENTRY (ID, ACL_OBJECT_IDENTITY, ACE_ORDER, SID, MASK, GRANTING, AUDIT_SUCCESS, AUDIT_FAILURE)
VALUES (10, 1000, 0, 99, 1, true, false, false);
Foo.java
package sample.spring.security.domain;
public class Foo {
private final long id;
public Foo(long id) {
this.id = id;
}
public long getId() {
return id;
}
@Override
public String toString() {
return "Foo{id=" + id + '}';
}
}
MyAclSampleService.java
package sample.spring.security.service;
import org.springframework.security.access.prepost.PreAuthorize;
import sample.spring.security.domain.Foo;
public class MyAclSampleService {
@PreAuthorize("hasPermission(#foo, read)")
public void logic(Foo foo) {
System.out.println("foo=" + foo);
}
}
foo
reçue comme argument
--Annotez la méthode avec @ PreAuthorize
et utilisez la fonction hasPermission ()
pour vérifier l'accès à l'objet de domaine.lecture
pour l'argument foo
MyAclServlet.java
package sample.spring.security.servlet;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import sample.spring.security.domain.Foo;
import sample.spring.security.service.MyAclSampleService;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.stream.Collectors;
@WebServlet("/acl")
public class MyAclServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.printPrincipal();
this.callServiceLogic(new Foo(44L), req);
this.callServiceLogic(new Foo(45L), req);
}
private void printPrincipal() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String name = auth.getName();
System.out.println("name=" + name);
System.out.println("authorities=" +
auth.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.joining(", "))
);
}
private void callServiceLogic(Foo foo, HttpServletRequest req) {
try {
this.findServiceBean(req).logic(foo);
} catch (AccessDeniedException e) {
System.out.println("AccessDeniedException : " + e.getMessage());
}
}
private MyAclSampleService findServiceBean(HttpServletRequest req) {
WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(req.getServletContext());
return context.getBean(MyAclSampleService.class);
}
}
namespace
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc.xsd">
<jdbc:embedded-database id="dataSource" type="H2">
<jdbc:script location="classpath:/sql/create_acl_tables.sql" />
<jdbc:script location="classpath:/sql/insert_acl_tables.sql" />
</jdbc:embedded-database>
<sec:global-method-security pre-post-annotations="enabled">
<sec:expression-handler ref="expressionHandler" />
</sec:global-method-security>
<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<property name="permissionEvaluator">
<bean class="org.springframework.security.acls.AclPermissionEvaluator">
<constructor-arg ref="aclService" />
</bean>
</property>
</bean>
<bean id="aclService" class="org.springframework.security.acls.jdbc.JdbcAclService">
<constructor-arg ref="dataSource" />
<constructor-arg ref="lookupStrategy" />
</bean>
<bean id="lookupStrategy" class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
<constructor-arg ref="dataSource" />
<constructor-arg ref="aclCache" />
<constructor-arg ref="aclAuthorizationStrategy" />
<constructor-arg ref="permissionGrantingStrategy" />
</bean>
<bean id="aclCache" class="org.springframework.security.acls.domain.SpringCacheBasedAclCache">
<constructor-arg>
<bean class="org.springframework.cache.support.NoOpCache">
<constructor-arg value="myCache" />
</bean>
</constructor-arg>
<constructor-arg ref="permissionGrantingStrategy" />
<constructor-arg ref="aclAuthorizationStrategy" />
</bean>
<bean id="aclAuthorizationStrategy" class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
<constructor-arg>
<list>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="TEST"/>
</bean>
</list>
</constructor-arg>
</bean>
<bean id="permissionGrantingStrategy" class="org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy">
<constructor-arg>
<bean class="org.springframework.security.acls.domain.ConsoleAuditLogger" />
</constructor-arg>
</bean>
<bean class="sample.spring.security.service.MyAclSampleService" />
<sec:http>
<sec:intercept-url pattern="/login" access="permitAll" />
<sec:intercept-url pattern="/**" access="isAuthenticated()" />
<sec:form-login />
<sec:logout />
</sec:http>
<sec:authentication-manager>
<sec:authentication-provider>
<sec:user-service>
<sec:user name="foo" password="foo" authorities="" />
<sec:user name="bar" password="bar" authorities="SAMPLE_AUTHORITY" />
</sec:user-service>
</sec:authentication-provider>
</sec:authentication-manager>
</beans
Java Configuration
MySpringSecurityConfig.java
package sample.spring.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import sample.spring.security.service.MyAclSampleService;
import java.util.Collections;
@EnableWebSecurity
@Import(MyGlobalMethodSecurityConfig.class)
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin();
}
@Bean
public MyAclSampleService myAclSampleService() {
return new MyAclSampleService();
}
@Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("foo")
.password("foo")
.authorities(Collections.emptyList())
.and()
.withUser("bar")
.password("bar")
.authorities("SAMPLE_AUTHORITY");
}
}
MyGlobalMethodSecurityConfig.java
package sample.spring.security;
import org.springframework.cache.support.NoOpCache;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.acls.AclPermissionEvaluator;
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
import org.springframework.security.acls.domain.ConsoleAuditLogger;
import org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy;
import org.springframework.security.acls.domain.SpringCacheBasedAclCache;
import org.springframework.security.acls.jdbc.BasicLookupStrategy;
import org.springframework.security.acls.jdbc.JdbcAclService;
import org.springframework.security.acls.jdbc.LookupStrategy;
import org.springframework.security.acls.model.AclCache;
import org.springframework.security.acls.model.AclService;
import org.springframework.security.acls.model.PermissionGrantingStrategy;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import javax.sql.DataSource;
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class MyGlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.generateUniqueName(true)
.setType(EmbeddedDatabaseType.H2)
.setScriptEncoding("UTF-8")
.addScripts("/sql/create_acl_tables.sql", "/sql/insert_acl_tables.sql")
.build();
}
@Bean
public PermissionEvaluator permissionEvaluator(AclService aclService) {
return new AclPermissionEvaluator(aclService);
}
@Bean
public AclService aclService(DataSource dataSource, LookupStrategy lookupStrategy) {
return new JdbcAclService(dataSource, lookupStrategy);
}
@Bean
public LookupStrategy lookupStrategy(DataSource dataSource, AclCache aclCache, AclAuthorizationStrategy aclAuthorizationStrategy, PermissionGrantingStrategy permissionGrantingStrategy) {
return new BasicLookupStrategy(
dataSource,
aclCache,
aclAuthorizationStrategy,
permissionGrantingStrategy
);
}
@Bean
public AclCache aclCache(PermissionGrantingStrategy permissionGrantingStrategy, AclAuthorizationStrategy aclAuthorizationStrategy) {
return new SpringCacheBasedAclCache(
new NoOpCache("myCache"),
permissionGrantingStrategy,
aclAuthorizationStrategy
);
}
@Bean
public AclAuthorizationStrategy aclAuthorizationStrategy() {
return new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("TEST"));
}
@Bean
public PermissionGrantingStrategy permissionGrantingStrategy() {
return new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger());
}
}
Connectez-vous en tant qu'utilisateur foo
et accédez à / acl
.
Sortie de la console du serveur
name=foo
authorities=
AccessDeniedException : Access is denied
AccessDeniedException : Access is denied
L'accès a été refusé pour ʻid = 44 et ʻid = 45
.
Puis connectez-vous en tant qu'utilisateur bar
et accédez à / acl
.
Sortie de la console du serveur
name=bar
authorities=SAMPLE_AUTHORITY
foo=Foo{id=44}
AccessDeniedException : Access is denied
ʻId = 44 a réussi à exécuter la méthode
logic () et ʻid = 45
a refusé l'accès.
Les quatre suivants apparaîtront.
ACL_SID
ACL_CLASS
ACL_OBJECT_IDENTITY
ACL_ENTRY
La structure du tableau ressemble à celle ci-dessous.
La flèche représente FK, la source de la flèche est la table de référence et la pointe de la flèche est la table de référence.
La signification de chaque tableau et colonne est la suivante.
ACL_CLASS
colonne | sens |
---|---|
CLASS |
Nom de classe Java (FQCN) de l'objet de domaine |
ACL_SID
GrantedAuthority
) ou
--SID signifie Security Identity
colonne | sens |
---|---|
PRINCIPAL |
Un indicateur qui distingue si cet enregistrement est un principaltrue → Directeurfalse → GrantedAuthority |
SID |
Une chaîne qui représente le SID. Si vous êtes un directeur username 、 GrantedAuthority Ensuite, l'expression de chaîne de caractères est définie |
ACL_OBJECT_IDENTITY --Table qui contient chaque instance d'un objet de domaine
colonne | sens |
---|---|
OBJECT_ID_CLASS |
Une colonne qui pointe vers une classe d'objets de domaine.ACL_CLASS Référence externe à. |
OBJECT_ID_IDENTITY |
ID qui identifie l'instance |
PARENT_OBJECT |
ParentsACL_OBJECT_IDENTITY ID |
OWNER_SID |
Créé cette instanceACL_SID ID |
ENTRIES_INHERITING |
Indique si cette instance a une relation d'héritage de privilèges avec d'autres instances |
ACL_ENTRY
pour chaque ʻACL_OBJECT_IDENTITY
colonne | sens |
---|---|
ACL_OBJECT_IDENTITY |
Appliquer cette définition d'autorisationACL_OBJECT_IDENTITY ID |
ACE_ORDER |
UnACL_OBJECT_IDENTITY À plusieursACL_ENTRTY Commander quand est lié |
SID |
Appliquer cette définition d'autorisationACL_SID ID |
MASK |
Valeur entière représentant la définition de l'autorisation (les détails seront décrits plus tard) |
GRANTING |
Indicateur "Accorder" ou "Rejeter" |
AUDIT_SUCCESS |
Indicateur de sortie du journal d'audit lorsque cette définition d'autorisation est accordée |
AUDIT_FAILUER |
Indicateur de sortie du journal d'audit lorsque cette définition d'autorisation est refusée |
Les données utilisées dans Hello World avaient une structure comme ↓.
--ʻACL_SID` Deux enregistrements sont enregistrés dans la table
hoge
et l'autre représente une autorité nommée SAMPLE_AUTHORITY
.
--Dans ʻACL_OBJECT_IDENTITY, un enregistrement représentant l'objet
Foo avec ʻid = 44
est enregistré.hoge
comme propriétairedéfinit les permissions à définir sur l'objet
Foo avec ʻid = 44
--MASK
est la définition de la permissionGRANTING
indique si la permission doit être "accordée" ou "refusée".SID
sur ʻACL_SID` pour appliquer les autorisationsSAMPLE_AUTHORITY
signifie "Si vous avez l'autorisation **
SAMPLE_AUTHORITY, vous pouvez lire l'objet
Foo avec ʻid = 44
**".--Un nombre doit être stocké dans ʻOBJECT_ID_IDENTITYcomme identifiant de l'objet de domaine. --Correspond au type
long` en Java
We do not intend to support non-long identifiers in Spring Security’s ACL module, as longs are already compatible with all database sequences, the most common identifier data type, and are of sufficient length to accommodate all common usage scenarios.
(Traduction) Nous n'avons pas l'intention de ** prendre en charge les identifiants non «longs» dans le module Spring Security ACL **.
long
est déjà compatible avec toutes les séquences de base de données, est le type de données le plus courant et est suffisamment long pour stocker tous les scénarios d'utilisation courants.
applicationContext.xml
<sec:global-method-security pre-post-annotations="enabled">
<sec:expression-handler ref="expressionHandler" />
</sec:global-method-security>
<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<property name="permissionEvaluator">
<bean class="org.springframework.security.acls.AclPermissionEvaluator">
<constructor-arg ref="aclService" />
</bean>
</property>
</bean>
hasPermission ()
dans des expressions telles que @ PreAuthorize ()
, vous devez étendre SecurityExpressionHandler
.
--L'expression hasPermission ()
est évaluée par PermissionEvaluator
--Cependant, la valeur par défaut «PermissionEvaluator» de «DefaultMethodSecurityExpressionHandler» est une classe appelée «DenyAllPermissionEvaluator», qui est implémentée de sorte que tous les résultats d'évaluation soient «faux».hasPermission ()
ne fonctionne pas par défaut (elle est toujours évaluée à false
).applicationContext.xml
<bean id="aclService" class="org.springframework.security.acls.jdbc.JdbcAclService">
<constructor-arg ref="dataSource" />
<constructor-arg ref="lookupStrategy" />
</bean>
--ʻAclService fournit la fonctionnalité ACL --
JdbcAclService` utilise JDBC pour accéder aux informations définies dans la base de données et implémenter la fonctionnalité ACL.
DataSource
comme argument de constructeurLookupStrategy
applicationContext.xml
<bean id="lookupStrategy" class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
<constructor-arg ref="dataSource" />
<constructor-arg ref="aclCache" />
<constructor-arg ref="aclAuthorizationStrategy" />
<constructor-arg ref="permissionGrantingStrategy" />
</bean>
) est délégué à
LookupStrategy au lieu de ʻAclService
lui-même.
--BasicLookupStrategy
est une implémentation qui utilise JDBC pour récupérer les informations de définition d'ACL.DataSource
comme argument de constructeurapplicationContext.xml
<bean id="aclCache" class="org.springframework.security.acls.domain.SpringCacheBasedAclCache">
<constructor-arg>
<bean class="org.springframework.cache.support.NoOpCache">
<constructor-arg value="myCache" />
</bean>
</constructor-arg>
<constructor-arg ref="permissionGrantingStrategy" />
<constructor-arg ref="aclAuthorizationStrategy" />
</bean>
SpringCacheBasedAclCache
et ʻEhCacheBasedAclCache`, sont fournies en standard.SpringCacheBasedAclCache
.
--Utilisation de NoOpCache
pour l'implémentation réelle du cacheNoOp
.--SpringCacheBasedAclCache
met en cache les objets de la classe ʻAclImpl`
AclImpl.java
private Acl parentAcl;
private transient AclAuthorizationStrategy aclAuthorizationStrategy;
private transient PermissionGrantingStrategy permissionGrantingStrategy;
private final List<AccessControlEntry> aces = new ArrayList<AccessControlEntry>();
private ObjectIdentity objectIdentity;
private Serializable id;
private Sid owner; // OwnershipAcl
private List<Sid> loadedSids = null; // includes all SIDs the WHERE clause covered,
--ʻAclImpl implémente l'interface ʻAcl
, et ʻAcl hérite de
Serializable`.
doit être sérialisable, et tous les champs ci-dessus sont fondamentalement sérialisables. --Cependant, ʻaclAuthorizationStrategy
et permissionGrantingStrategy
sont qualifiés de transient
, donc ils sont exclus de la sérialisation.et de
PermissionGrantingStrategy au cache en tant qu'arguments du constructeur. --L'instance spécifiée ici est utilisée pour reconfigurer lorsque ʻAclImpl
est retiré du cache.Au fait, BasicLookupStrategy
doit également recevoir des instances de ʻAclAuthorizationStrategy et de
PermissionGrantingStrategy` comme arguments de constructeur.
applicationContext.xml
<bean id="lookupStrategy" class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
...
<constructor-arg ref="aclAuthorizationStrategy" />
<constructor-arg ref="permissionGrantingStrategy" />
</bean>
Ceci est utilisé pour définir lorsque BasicLookupStrategy
reconstruit l'objet ʻAclImpl` à partir des informations de la base de données.
AclAuthorizationStrategy
applicationContext.xml
<bean id="aclAuthorizationStrategy" class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
<constructor-arg>
<list>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="TEST"/>
</bean>
</list>
</constructor-arg>
</bean>
--ʻAclAuthorizationStrategy` a le rôle de vérifier si le principal actuel a cette autorité lors de la modification de la définition d'une ACL. ――En d'autres termes, il n'est pas réellement utilisé dans ce Hello World
PermissionGrantingStrategy
applicationContext.xml
<bean id="permissionGrantingStrategy" class="org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy">
<constructor-arg>
<bean class="org.springframework.security.acls.domain.ConsoleAuditLogger" />
</constructor-arg>
</bean>
--PermissionGrantingStrategy
fournit un processus pour déterminer spécifiquement si le principal actuel a les autorisations spécifiées parhasPermission ()
.
AuditLogger
--ʻAuditLogger fournit un processus pour enregistrer le résultat du jugement d'autorisation. --
ConsoleAuditLogger` est la seule classe d'implémentation fournie et affiche le résultat sur la console.
Comme ça.
hasPermission()
MyAclSampleService.java
@PreAuthorize("hasPermission(#foo, read)")
public void logic(Foo foo) {
--Utilisez l'expression hasPermission ()
pour déterminer l'ACL
--Spécifiez l'objet de domaine dans le premier argument et l'autorisation dans le deuxième argument
hasPermission ()
, le module ACL recherche une méthode appeléegetId ()
dans l'objet de domaine par réflexion.Serializable
long getId ()
dans l'objet de domaine.MyAclSampleService.java
@PreAuthorize("hasPermission(#id, 'sample.spring.security.domain.Foo', read)")
public void logic(long id) {
hasPermission ()
pour spécifier l'ID lorsque vous n'avez pas encore créé une instance de l'objet de domaine.--La constante read
est spécifiée pour spécifier l'autorisation.
SecurityExpressionRoot
SecurityExpressionRoot.java
public final String read = "read";
public final String write = "write";
public final String create = "create";
public final String delete = "delete";
public final String admin = "administration";
Les définitions des autorisations («lecture», «écriture», «création», «suppression», «administration») sont exprimées sous forme de valeurs entières.
Sur la base de données, il est stocké dans la colonne MASK
de ʻACL_ENTRY`.
Chaque autorisation est associée à chaque bit binaire comme indiqué ci-dessous.
5ème bit | 4e bit | 3e bit | 2ème bit | 1er bit |
---|---|---|---|---|
administration | delete | create | write | read |
En d'autres termes
autorisation | Représentation binaire | Représentation décimale |
---|---|---|
read |
00001 |
1 |
write |
00010 |
2 |
create |
00100 |
4 |
delete |
01000 |
8 |
administration |
10000 |
16 |
Vous pourriez vous demander: "Alors, si vous voulez avoir deux permissions," read "et" write ", est-ce" 00011 "(" 3 "en décimal)?", Mais ce n'est pas le cas.
Au dernier, l'un des cinq ci-dessus est entré dans MASK
de chaque enregistrement ʻACL_ENTRY`.
Lors de l'octroi de plusieurs autorisations, le nombre d'enregistrements sera enregistré.
(Est-ce un masque?)
Des données d'entrée
INSERT INTO ACL_CLASS (ID, CLASS)
VALUES (100, 'sample.spring.security.domain.Foo');
INSERT INTO ACL_SID (ID, PRINCIPAL, SID)
VALUES (9, true, 'hoge');
INSERT INTO ACL_SID (ID, PRINCIPAL, SID)
VALUES (98, false, 'AUTHORITY_10101');
INSERT INTO ACL_SID (ID, PRINCIPAL, SID)
VALUES (99, false, 'AUTHORITY_01010');
INSERT INTO ACL_OBJECT_IDENTITY (ID, OBJECT_ID_CLASS, OBJECT_ID_IDENTITY, PARENT_OBJECT, OWNER_SID, ENTRIES_INHERITING)
VALUES (1000, 100, 44, NULL, 9, true);
-- AUTHORITY_10101
INSERT INTO ACL_ENTRY (ID, ACL_OBJECT_IDENTITY, ACE_ORDER, SID, MASK, GRANTING, AUDIT_SUCCESS, AUDIT_FAILURE)
VALUES (10, 1000, 0, 98, 1, true, false, false); -- read(00001 = 1)
INSERT INTO ACL_ENTRY (ID, ACL_OBJECT_IDENTITY, ACE_ORDER, SID, MASK, GRANTING, AUDIT_SUCCESS, AUDIT_FAILURE)
VALUES (11, 1000, 1, 98, 4, true, false, false); -- create(00100 = 4)
INSERT INTO ACL_ENTRY (ID, ACL_OBJECT_IDENTITY, ACE_ORDER, SID, MASK, GRANTING, AUDIT_SUCCESS, AUDIT_FAILURE)
VALUES (12, 1000, 2, 98, 16, true, false, false); -- administration(10000 = 16)
-- AUTHORITY_01010
INSERT INTO ACL_ENTRY (ID, ACL_OBJECT_IDENTITY, ACE_ORDER, SID, MASK, GRANTING, AUDIT_SUCCESS, AUDIT_FAILURE)
VALUES (13, 1000, 3, 99, 10, true, false, false); -- write, delete(01010 = 10)
read (1)
, create (4)
et ʻadministration (16) individuellement à ʻAUTHORITY_10101
.
--Ajoutez 01010 = 10
à ʻAUTHORITY_01010, qui est une combinaison des permissions de
write (2) ʻet delete (8)
.applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
...>
...
<sec:authentication-manager>
<sec:authentication-provider>
<sec:user-service>
<sec:user name="foo" password="foo" authorities="AUTHORITY_10101" />
<sec:user name="bar" password="bar" authorities="AUTHORITY_01010" />
</sec:user-service>
</sec:authentication-provider>
</sec:authentication-manager>
</beans>
foo
a l'autorité de ʻAUTHORITY_10101`, à l'utilisateur
bar`MyAclSampleService.java
package sample.spring.security.service;
import org.springframework.security.access.prepost.PreAuthorize;
import sample.spring.security.domain.Foo;
public class MyAclSampleService {
@PreAuthorize("hasPermission(#foo, read)")
public void read(Foo foo) {
System.out.println("[read] foo=" + foo);
}
@PreAuthorize("hasPermission(#foo, write)")
public void write(Foo foo) {
System.out.println("[write] foo=" + foo);
}
@PreAuthorize("hasPermission(#foo, create)")
public void create(Foo foo) {
System.out.println("[create] foo=" + foo);
}
@PreAuthorize("hasPermission(#foo, delete)")
public void delete(Foo foo) {
System.out.println("[delete] foo=" + foo);
}
@PreAuthorize("hasPermission(#foo, admin)")
public void admin(Foo foo) {
System.out.println("[admin] foo=" + foo);
}
}
--Spécifiez les autorisations requises avec hasPermission ()
pour chaque méthode
MyAclServlet.java
package sample.spring.security.servlet;
...
@WebServlet("/acl")
public class MyAclServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.printPrincipal();
MyAclSampleService serviceBean = this.findServiceBean(req);
Foo foo = new Foo(44L);
this.callServiceLogic("read", () -> serviceBean.read(foo));
this.callServiceLogic("write", () -> serviceBean.write(foo));
this.callServiceLogic("create", () -> serviceBean.create(foo));
this.callServiceLogic("delete", () -> serviceBean.delete(foo));
this.callServiceLogic("admin", () -> serviceBean.admin(foo));
}
private void printPrincipal() {
...
}
private void callServiceLogic(String methodName, Runnable runnable) {
try {
System.out.println("* invoke " + methodName + "()");
runnable.run();
} catch (AccessDeniedException e) {
System.out.println("AccessDeniedException : " + e.getMessage());
}
}
private MyAclSampleService findServiceBean(HttpServletRequest req) {
...
}
}
MyAclSampleService
et affichez le résultat dans la sortie standard.** Contrôle de fonctionnement **
Sortie du serveur lors de la connexion avec foo
name=foo
authorities=AUTHORITY_10101
* invoke read()
[read] foo=Foo{id=44}
* invoke write()
AccessDeniedException : Access is denied
* invoke create()
[create] foo=Foo{id=44}
* invoke delete()
AccessDeniedException : Access is denied
* invoke admin()
[admin] foo=Foo{id=44}
Sortie du serveur lors de la connexion avec bar
name=bar
authorities=AUTHORITY_01010
* invoke read()
AccessDeniedException : Access is denied
* invoke write()
AccessDeniedException : Access is denied
* invoke create()
AccessDeniedException : Access is denied
* invoke delete()
AccessDeniedException : Access is denied
* invoke admin()
AccessDeniedException : Access is denied
--write
et delete
ont également été bloqués
La raison a été décrite dans Ce problème sur GitHub.
Je suis sceptique que cela me convienne parce que ma capacité en anglais est faible, mais j'ai l'impression que c'est comme suit.
Donc, même s'il dit «MASK», cela ressemble en fait à une division de valeurs entières.
Après tout, "J'ai préparé un point d'extension, donc si vous voulez vraiment juger avec un peu de masque, veuillez l'utiliser." SEC-1166: Provide strategy interface for AclImpl isGranted() method.
Jusqu'à ce point, des données telles que ʻACL_ENTRY` étaient enregistrées en préparant une instruction INSERT dans SQL à l'avance.
Cependant, il est difficile d'éditer ces tableaux directement dans le développement réel car vous devez comprendre correctement les spécifications.
Par conséquent, il existe une API pour maintenir ces données.
MyAclSampleService.java
package sample.spring.security.service;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.MutableAclService;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.transaction.annotation.Transactional;
import sample.spring.security.domain.Foo;
@Transactional
public class MyAclSampleService {
private MutableAclService aclService;
public MyAclSampleService(MutableAclService aclService) {
this.aclService = aclService;
}
public void createObjectIdentity() {
ObjectIdentity objectIdentity = new ObjectIdentityImpl(Foo.class, 10L);
MutableAcl acl = this.aclService.createAcl(objectIdentity);
System.out.println("acl = " + acl);
}
}
MyAclServlet.java
package sample.spring.security.servlet;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import sample.spring.security.service.MyAclSampleService;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;
@WebServlet("/acl")
public class MyAclServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
MyAclSampleService service = this.findServiceBean(req, MyAclSampleService.class);
service.createObjectIdentity();
this.printTables(req);
}
private void printTables(HttpServletRequest req) {
this.printTable(req, "ACL_SID");
this.printTable(req, "ACL_CLASS");
this.printTable(req, "ACL_OBJECT_IDENTITY");
this.printTable(req, "ACL_ENTRY");
}
private void printTable(HttpServletRequest req, String table) {
JdbcTemplate jdbcTemplate = this.findServiceBean(req, JdbcTemplate.class);
List<Map<String, Object>> records = jdbcTemplate.queryForList("select * from " + table + " order by id asc");
System.out.println("\n[" + table + "]");
records.forEach(System.out::println);
}
private <T> T findServiceBean(HttpServletRequest req, Class<T> clazz) {
WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(req.getServletContext());
return context.getBean(clazz);
}
}
namespace
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<tx:annotation-driven />
<jdbc:embedded-database id="dataSource" type="H2">
<jdbc:script location="classpath:/sql/create_acl_tables.sql" />
</jdbc:embedded-database>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource" />
</bean>
...
<bean id="aclService" class="org.springframework.security.acls.jdbc.JdbcMutableAclService">
<constructor-arg ref="dataSource" />
<constructor-arg ref="lookupStrategy" />
<constructor-arg ref="aclCache" />
</bean>
...
<bean class="sample.spring.security.service.MyAclSampleService">
<constructor-arg ref="aclService" />
</bean>
<bean class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSource" />
</bean>
...
</beans>
Java Configuration
MySpringSecurityConfig.java
package sample.spring.security;
...
import org.springframework.security.acls.model.MutableAclService;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import sample.spring.security.service.MyAclSampleService;
...
@EnableWebSecurity
@EnableTransactionManagement
@Import(MyGlobalMethodSecurityConfig.class)
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
...
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean
public MyAclSampleService myAclSampleService(MutableAclService aclService) {
return new MyAclSampleService(aclService);
}
...
}
MyGlobalMethodSecurityConfig.java
package sample.spring.security;
...
import org.springframework.security.acls.jdbc.JdbcMutableAclService;
...
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class MyGlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration {
...
@Bean
public AclService aclService(DataSource dataSource, LookupStrategy lookupStrategy, AclCache aclCache) {
return new JdbcMutableAclService(dataSource, lookupStrategy, aclCache);
}
...
}
Accès pour exécuter MyAclServlet
.
Sortie de la console du serveur
acl = AclImpl[
id: 1;
objectIdentity: org.springframework.security.acls.domain.ObjectIdentityImpl[
Type: sample.spring.security.domain.Foo;
Identifier: 10
];
owner: PrincipalSid[
foo
];
no ACEs;
inheriting: true;
parent: Null;
aclAuthorizationStrategy: org.springframework.security.acls.domain.AclAuthorizationStrategyImpl@2c7d9da4;
permissionGrantingStrategy: org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy@634b81ac
]
[ACL_SID]
{ID=1, PRINCIPAL=true, SID=foo}
[ACL_CLASS]
{ID=1, CLASS=sample.spring.security.domain.Foo}
[ACL_OBJECT_IDENTITY]
{ID=1, OBJECT_ID_CLASS=1, OBJECT_ID_IDENTITY=10, PARENT_OBJECT=null, OWNER_SID=1, ENTRIES_INHERITING=true}
[ACL_ENTRY]
* La sortie d'Acl est en fait sortie sur une seule ligne, mais des sauts de ligne sont ajoutés pour faciliter la visualisation </ font>
MyAclSampleService.java
package sample.spring.security.service;
...
import org.springframework.transaction.annotation.Transactional;
...
@Transactional
public class MyAclSampleService {
...
--Annoter la classe avec @ Transactional
namespace
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans ...
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
...
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<tx:annotation-driven />
...
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg ref="dataSource" />
</bean>
...
--Activez les transactions basées sur les annotations avec <annotation-driven>
PlatformTransactionManager
( DataSourceTransactionManager
) avec le nom transactionManager
.Java Configuration
MySpringSecurityConfig.java
...
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
...
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
...
@EnableTransactionManagement
...
public class MySpringSecurityConfig extends WebSecurityConfigurerAdapter {
...
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@ EnableTransactionManagement
DataSourceTransactionManager
, qui est une implémentation de PlatformTransactionManager
, en tant que bean.namespace
applicationContext.xml
<bean id="aclService" class="org.springframework.security.acls.jdbc.JdbcMutableAclService">
<constructor-arg ref="dataSource" />
<constructor-arg ref="lookupStrategy" />
<constructor-arg ref="aclCache" />
</bean>
Java Configuration
MyGlobalMethodSecurityConfig.java
import org.springframework.security.acls.jdbc.JdbcMutableAclService;
...
@Bean
public AclService aclService(DataSource dataSource, LookupStrategy lookupStrategy, AclCache aclCache) {
return new JdbcMutableAclService(dataSource, lookupStrategy, aclCache);
}
--Il existe une classe appelée JdbcMutableAclService
avec une méthode de mise à jour des ACL en tant que sous-classe de JdbcAclService
.
--Enregistrez un objet de cette classe en tant que bean au lieu de JdbcAclService
dans l'argument constructeur, ce qui est nécessaire car
JdbcMutableAclService` supprime également ces informations du cache lorsque vous effectuez le processus de suppression de l'ACL.MyAclSampleService.java
package sample.spring.security.service;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.MutableAclService;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.transaction.annotation.Transactional;
import sample.spring.security.domain.Foo;
@Transactional
public class MyAclSampleService {
private MutableAclService aclService;
public MyAclSampleService(MutableAclService aclService) {
this.aclService = aclService;
}
public void createObjectIdentity() {
ObjectIdentity objectIdentity = new ObjectIdentityImpl(Foo.class, 10L);
MutableAcl acl = this.aclService.createAcl(objectIdentity);
System.out.println("acl = " + acl);
}
}
--Créer un objet de ʻObjectIdentity (ʻObjectIdentityImpl
)
--ʻLe constructeur d'ObjectIdeneityImpla le premier objet
Class` de l'objet de domaine,
) --Passez le ʻObjectIdentity
créé à la méthodecreateAcl (ObjectIdentity)
de MutableAclService
lorsque
createAcl () est exécuté. --ʻACL_CLASS
est également créé si l'information n'existe pas
--Retourné MutableAcl
Sortie de la console du serveur
[ACL_SID]
{ID=1, PRINCIPAL=true, SID=foo}
[ACL_CLASS]
{ID=1, CLASS=sample.spring.security.domain.Foo}
[ACL_OBJECT_IDENTITY]
{ID=1, OBJECT_ID_CLASS=1, OBJECT_ID_IDENTITY=10, PARENT_OBJECT=null, OWNER_SID=1, ENTRIES_INHERITING=true}
{ID=2, OBJECT_ID_CLASS=1, OBJECT_ID_IDENTITY=11, PARENT_OBJECT=null, OWNER_SID=1, ENTRIES_INHERITING=true}
[ACL_ENTRY]
--Si vous regardez attentivement, le ʻOWNER_SID du ʻACL_OBJECT_IDENTITY
créé est mis à ʻACL_SID of
SID = foo`.
createAcl ()
de MutableAclService
est exécuté.Les informations ACL sont modélisées dans la structure de classe ci-dessous.
ObjectIdentity
--Un objet qui représente l'identifiant d'un objet de domaineAcl
--L'objet principal de l'ACL
--Inclut toutes les autorisations associées à ʻObjectIdentity`AccessControlEntry
--Un objet qui représente les autorisations individuelles attribuées à Sid
pour ʻAcl`Permission
--Un objet avec des informations d'autorisation spécifiquesSid
--Un objet qui représente la cible à laquelle les autorisations sont attribuéesLorsque createAcl ()
de MutableAclService
est exécuté, ʻAcl, ʻAccessControlEntry
, Permission
et Sid
sont construits sous la forme associée à ʻObjectIdentity` spécifiée par l'argument.
MyAclSampleService.java
package sample.spring.security.service;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.model.Acl;
...
public class MyAclSampleService {
private MutableAclService aclService;
...
public void createObjectIdentity() {
...
}
public void findAcl() {
ObjectIdentity objectIdentity = new ObjectIdentityImpl(Foo.class, 10L);
Acl acl = aclService.readAclById(objectIdentity);
System.out.println("acl = " + acl);
}
}
MyAclServlet.java
package sample.spring.security.servlet;
...
@WebServlet("/acl")
public class MyAclServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
MyAclSampleService service = this.findServiceBean(req, MyAclSampleService.class);
service.createObjectIdentity();
this.printTables(req);
service.findAcl();
}
...
}
Sortie de la console du serveur (createObjectIdeneity)()La sortie est omise)
acl = AclImpl[
id: 1;
objectIdentity: org.springframework.security.acls.domain.ObjectIdentityImpl[
Type: sample.spring.security.domain.Foo;
Identifier: 10
];
owner: PrincipalSid[
foo
];
no ACEs;
inheriting: true;
parent: Null;
aclAuthorizationStrategy: org.springframework.security.acls.domain.AclAuthorizationStrategyImpl@2c7d9da4;
permissionGrantingStrategy: org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy@634b81ac
]
MyAclSampleService.java
public void findAcl() {
ObjectIdentity objectIdentity = new ObjectIdentityImpl(Foo.class, 10L);
Acl acl = aclService.readAclById(objectIdentity);
System.out.println("acl = " + acl);
}
--ʻAclService fournit une méthode pour rechercher ʻAcl
associé à ʻObjectIdentity
avecreadAclById (ObjectIdentity)
.MyAclSampleService.java
package sample.spring.security.service;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.acls.domain.GrantedAuthoritySid;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.domain.PrincipalSid;
import org.springframework.security.acls.model.AccessControlEntry;
import org.springframework.security.acls.model.Acl;
import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.MutableAclService;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.transaction.annotation.Transactional;
import sample.spring.security.domain.Foo;
import java.util.List;
@Transactional
public class MyAclSampleService {
private MutableAclService aclService;
...
public void createObjectIdentity() {
...
}
public void findAcl() {
...
}
public void addPermission() {
//Recherchez l'ACL à mettre à jour et
ObjectIdentity objectIdentity = new ObjectIdentityImpl(Foo.class, 10L);
MutableAcl acl = (MutableAcl) aclService.readAclById(objectIdentity);
//Autorité"HOGE_AUTHORITY"Accordez les autorisations CREATE à
List<AccessControlEntry> entries = acl.getEntries();
GrantedAuthoritySid grantedAuthoritySid = new GrantedAuthoritySid(new SimpleGrantedAuthority("HOGE_AUTHORITY"));
acl.insertAce(entries.size(), BasePermission.CREATE, grantedAuthoritySid, true);
//Principal"test_user"Accorder l'autorisation WRITE à
PrincipalSid principalSid = new PrincipalSid("test_user");
acl.insertAce(entries.size(), BasePermission.WRITE, principalSid, true);
//Enregistrer les modifications de l'ACL
this.aclService.updateAcl(acl);
System.out.println("acl = " + acl);
}
}
MyAclServlet.java
package sample.spring.security.servlet;
...
@WebServlet("/acl")
public class MyAclServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
MyAclSampleService service = this.findServiceBean(req, MyAclSampleService.class);
service.createObjectIdentity();
this.printTables(req);
service.findAcl();
service.addPermission();
this.printTables(req);
}
...
}
Sortie de la console du serveur
★ Avant d'ajouter des autorisations
acl = AclImpl[
id: 1;
objectIdentity: org.springframework.security.acls.domain.ObjectIdentityImpl[
Type: sample.spring.security.domain.Foo;
Identifier: 10
];
owner: PrincipalSid[
foo
];
no ACEs;
inheriting: true;
parent: Null;
aclAuthorizationStrategy: org.springframework.security.acls.domain.AclAuthorizationStrategyImpl@162ff71c;
permissionGrantingStrategy: org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy@742976d3
]
[ACL_SID]
{ID=1, PRINCIPAL=true, SID=foo}
[ACL_CLASS]
{ID=1, CLASS=sample.spring.security.domain.Foo}
[ACL_OBJECT_IDENTITY]
{ID=1, OBJECT_ID_CLASS=1, OBJECT_ID_IDENTITY=10, PARENT_OBJECT=null, OWNER_SID=1, ENTRIES_INHERITING=true}
[ACL_ENTRY]
...
★ Après avoir ajouté des autorisations
acl = AclImpl[
id: 1;
objectIdentity: org.springframework.security.acls.domain.ObjectIdentityImpl[
Type: sample.spring.security.domain.Foo;
Identifier: 10
];
owner: PrincipalSid[
foo
];
AccessControlEntryImpl[
id: null;
granting: true;
sid: PrincipalSid[
test_user
];
permission: BasePermission[
..............................W.=2
];
auditSuccess: false;
auditFailure: false
]
AccessControlEntryImpl[
id: null;
granting: true;
sid: GrantedAuthoritySid[
HOGE_AUTHORITY
];
permission: BasePermission[
.............................C..=4
];
auditSuccess: false;
auditFailure: false
]
inheriting: true;
parent: Null;
aclAuthorizationStrategy: org.springframework.security.acls.domain.AclAuthorizationStrategyImpl@162ff71c;
permissionGrantingStrategy: org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy@742976d3
]
[ACL_SID]
{ID=1, PRINCIPAL=true, SID=foo}
{ID=2, PRINCIPAL=true, SID=test_user}
{ID=3, PRINCIPAL=false, SID=HOGE_AUTHORITY}
[ACL_CLASS]
{ID=1, CLASS=sample.spring.security.domain.Foo}
[ACL_OBJECT_IDENTITY]
{ID=1, OBJECT_ID_CLASS=1, OBJECT_ID_IDENTITY=10, PARENT_OBJECT=null, OWNER_SID=1, ENTRIES_INHERITING=true}
[ACL_ENTRY]
{ID=1, ACL_OBJECT_IDENTITY=1, ACE_ORDER=0, SID=2, MASK=2, GRANTING=true, AUDIT_SUCCESS=false, AUDIT_FAILURE=false}
{ID=2, ACL_OBJECT_IDENTITY=1, ACE_ORDER=1, SID=3, MASK=4, GRANTING=true, AUDIT_SUCCESS=false, AUDIT_FAILURE=false}
MyAclSampleService.java
public void addPermission() {
//Recherchez l'ACL à mettre à jour et
ObjectIdentity objectIdentity = new ObjectIdentityImpl(Foo.class, 10L);
MutableAcl acl = (MutableAcl) aclService.readAclById(objectIdentity);
//Autorité"HOGE_AUTHORITY"Accordez les autorisations CREATE à
List<AccessControlEntry> entries = acl.getEntries();
GrantedAuthoritySid grantedAuthoritySid = new GrantedAuthoritySid(new SimpleGrantedAuthority("HOGE_AUTHORITY"));
acl.insertAce(entries.size(), BasePermission.CREATE, grantedAuthoritySid, true);
//Principal"test_user"Accorder l'autorisation WRITE à
PrincipalSid principalSid = new PrincipalSid("test_user");
acl.insertAce(entries.size(), BasePermission.WRITE, principalSid, true);
//Enregistrer les modifications de l'ACL
this.aclService.updateAcl(acl);
System.out.println("acl = " + acl);
}
en exécutant ʻinsertAce (int, Permission, Sid, boolean)
de MutableAcl
. est ajouté à ʻAcl
.) sont conservées en interne dans ʻAcl
as List
et sont passées au premier argument de la méthode ʻadd (int, E) . --Donc, si vous passez une valeur inférieure à "0" ou supérieure à "size ()", une erreur se produira (si elle est identique à "size ()", elle sera ajoutée à la fin). --Dans DB, il devient ʻACE_ORDER
de ʻACL_ENTRY --
Permission peut spécifier les constantes définies dans la classe d'implémentation
BasePermission --
Sid spécifie
GrantedAuthoritySidou
PrincipalSid--Si vous souhaitez attribuer des autorisations aux autorisations
GrantedAuthoritySid--Utilisez
PrincipalSid` pour attribuer des autorisations aux principauxbooléen
spécifie si la permission doit être" accordée "ou" refusée ".MyAclSampleService.java
package sample.spring.security.service;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.acls.domain.GrantedAuthoritySid;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.MutableAclService;
import org.springframework.security.acls.model.NotFoundException;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.transaction.annotation.Transactional;
import sample.spring.security.domain.Foo;
@Transactional
public class MyAclSampleService {
private MutableAclService aclService;
public MyAclSampleService(MutableAclService aclService) {
this.aclService = aclService;
}
public void addPermission() {
ObjectIdentity objectIdentity = new ObjectIdentityImpl(Foo.class, 10L);
try {
this.aclService.readAclById(objectIdentity);
} catch (NotFoundException e) {
MutableAcl acl = this.aclService.createAcl(objectIdentity);
GrantedAuthoritySid deniedRead = new GrantedAuthoritySid(new SimpleGrantedAuthority("DENIED_READ"));
acl.insertAce(0, BasePermission.READ, deniedRead, false);
GrantedAuthoritySid permitRead = new GrantedAuthoritySid(new SimpleGrantedAuthority("PERMIT_READ"));
acl.insertAce(1, BasePermission.READ, permitRead, true);
this.aclService.updateAcl(acl);
}
}
@PreAuthorize("hasPermission(#foo, read)")
public void read(Foo foo) {
System.out.println("read(" + foo + ")");
}
}
readAclById ()
ne peut pas obtenir l'ACL et NotFoundException
est levée, alors enregistrez l'autorisation uniquement à ce moment-là.
--Enregistrez l'autorité read
avec" deny "dans l'autorité DENIED_READ
,
--Pour l'autorité PERMIT_READ
, l'autorité read
est enregistrée avec" Grant ".DENIED_READ
à 0
pour qu'il vienne en premier.read ()
est annotée avec @ PreAuthorize
, et hasPermission ()
vérifie si vous avez les privilèges read
.package sample.spring.security.servlet;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import sample.spring.security.domain.Foo;
import sample.spring.security.service.MyAclSampleService;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@WebServlet("/acl")
public class MyAclServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.printPrincipal();
MyAclSampleService service = this.findServiceBean(req, MyAclSampleService.class);
service.addPermission();
this.printTables(req);
try {
service.read(new Foo(10L));
} catch (AccessDeniedException e) {
System.out.println(e.getMessage());
}
}
...
}
printPrincipal ()
)
--Enregistrer ACL (ʻaddPermission () `)printTables ()
)read ()
et affichez un message si ʻAccessDeniedException` est lancé.la mise en oeuvre
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
...>
...
<sec:authentication-manager>
<sec:authentication-provider>
<sec:user-service>
<sec:user name="foo" password="foo" authorities="PERMIT_READ" />
<sec:user name="bar" password="bar" authorities="PERMIT_READ,DENIED_READ" />
</sec:user-service>
</sec:authentication-provider>
</sec:authentication-manager>
</beans>
--Définissez deux utilisateurs, foo
et bar
--Définissez l'autorisation PERMIT_READ
pour l'utilisateur foo
--Définissez les autorisations PERMIT_READ
et DENIED_READ
sur l'utilisateur bar
Connectez-vous en tant qu'utilisateur foo
et accédez à / acl
.
Sortie de la console du serveur
name=foo
authorities=PERMIT_READ
[ACL_SID]
{ID=1, PRINCIPAL=true, SID=foo}
{ID=2, PRINCIPAL=false, SID=DENIED_READ}
{ID=3, PRINCIPAL=false, SID=PERMIT_READ}
[ACL_CLASS]
{ID=1, CLASS=sample.spring.security.domain.Foo}
[ACL_OBJECT_IDENTITY]
{ID=1, OBJECT_ID_CLASS=1, OBJECT_ID_IDENTITY=10, PARENT_OBJECT=null, OWNER_SID=1, ENTRIES_INHERITING=true}
[ACL_ENTRY]
{ID=1, ACL_OBJECT_IDENTITY=1, ACE_ORDER=0, SID=2, MASK=1, GRANTING=false, AUDIT_SUCCESS=false, AUDIT_FAILURE=false}
{ID=2, ACL_OBJECT_IDENTITY=1, ACE_ORDER=1, SID=3, MASK=1, GRANTING=true, AUDIT_SUCCESS=false, AUDIT_FAILURE=false}
read(Foo{id=10})
La méthode read ()
peut être exécutée
Puis connectez-vous en tant qu'utilisateur bar
et accédez à / acl
.
Sortie de la console du serveur
name=bar
authorities=DENIED_READ, PERMIT_READ
[ACL_SID]
{ID=1, PRINCIPAL=true, SID=foo}
{ID=2, PRINCIPAL=false, SID=DENIED_READ}
{ID=3, PRINCIPAL=false, SID=PERMIT_READ}
[ACL_CLASS]
{ID=1, CLASS=sample.spring.security.domain.Foo}
[ACL_OBJECT_IDENTITY]
{ID=1, OBJECT_ID_CLASS=1, OBJECT_ID_IDENTITY=10, PARENT_OBJECT=null, OWNER_SID=1, ENTRIES_INHERITING=true}
[ACL_ENTRY]
{ID=1, ACL_OBJECT_IDENTITY=1, ACE_ORDER=0, SID=2, MASK=1, GRANTING=false, AUDIT_SUCCESS=false, AUDIT_FAILURE=false}
{ID=2, ACL_OBJECT_IDENTITY=1, ACE_ORDER=1, SID=3, MASK=1, GRANTING=true, AUDIT_SUCCESS=false, AUDIT_FAILURE=false}
Access is denied
L'accès a été refusé.
MyAclSampleService.java
MutableAcl acl = this.aclService.createAcl(objectIdentity);
GrantedAuthoritySid deniedRead = new GrantedAuthoritySid(new SimpleGrantedAuthority("DENIED_READ"));
acl.insertAce(0, BasePermission.READ, deniedRead, false);
GrantedAuthoritySid permitRead = new GrantedAuthoritySid(new SimpleGrantedAuthority("PERMIT_READ"));
acl.insertAce(1, BasePermission.READ, permitRead, true);
this.aclService.updateAcl(acl);
applicationContext.xml
<sec:user name="foo" password="foo" authorities="PERMIT_READ" />
<sec:user name="bar" password="bar" authorities="PERMIT_READ,DENIED_READ" />
--ʻACE_ORDER` semble être appliqué avec la priorité donnée à la commande
bar
a également été défini sur PERMIT_READ
, mais la permission a été déterminée comme étant" refusée "car" DENIED_READ précédait
PERMIT_READ par ʻACE_ORDER
.HenLorsque j'ai vu ce mécanisme pour la première fois (refuser l'autorisation et la commande ʻACE`), je ne pouvais pas penser à une grande utilité.
GrantedAuthority
), cela se comportera comme" fondamentalement, vous ne pourrez pas accéder si vous avez cette permission ".
――Je ne sais pas s'il existe une telle situation, mais lorsque vous souhaitez essentiellement refuser l'accès, je pense que vous pouvez contrôler des choses comme "vous pouvez désactiver l'accès en définissant cette autorisation"Tout le monde ne peut pas mettre à jour l'ACL.
src/main/resources/sql/insert_acl_tables.sql
INSERT INTO ACL_CLASS (ID, CLASS)
VALUES (100, 'sample.spring.security.domain.Foo');
INSERT INTO ACL_SID (ID, PRINCIPAL, SID)
VALUES (9, true, 'hoge');
INSERT INTO ACL_SID (ID, PRINCIPAL, SID)
VALUES (19, true, 'admin');
INSERT INTO ACL_OBJECT_IDENTITY (ID, OBJECT_ID_CLASS, OBJECT_ID_IDENTITY, PARENT_OBJECT, OWNER_SID, ENTRIES_INHERITING)
VALUES (1000, 100, 10, NULL, 9, true);
INSERT INTO ACL_ENTRY (ID, ACL_OBJECT_IDENTITY, ACE_ORDER, SID, MASK, GRANTING, AUDIT_SUCCESS, AUDIT_FAILURE)
VALUES (10000, 1000, 0, 19, 16, true, false, false); --admin utilisateur admin(16)Donner la permission
--Créez ʻACL_OBJECT_IDENTITY pour l'objet
Foo avec ʻID = 10
--Définir le principal hoge
comme propriétaire
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
...>
...
<jdbc:embedded-database id="dataSource" type="H2">
<jdbc:script location="classpath:/sql/create_acl_tables.sql" />
<jdbc:script location="classpath:/sql/insert_acl_tables.sql" />
</jdbc:embedded-database>
...
<bean id="aclAuthorizationStrategy" class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
<constructor-arg>
<list>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="PERMISSION_MANAGER"/>
</bean>
</list>
</constructor-arg>
</bean>
...
<sec:authentication-manager>
<sec:authentication-provider>
<sec:user-service>
<sec:user name="hoge" password="hoge" authorities="" />
<sec:user name="fuga" password="fuga" authorities="" />
<sec:user name="piyo" password="piyo" authorities="PERMISSION_MANAGER" />
<sec:user name="admin" password="admin" authorities="" />
</sec:user-service>
</sec:authentication-provider>
</sec:authentication-manager>
</beans>
--ʻAclAuthorizationStrategyImplpasse
PERMISSION_MANAGER` comme argument de constructeur
hoge
, fuga
, ʻadmin` n'a pas de privilègesPERMISSION_MANAGER
uniquement aux utilisateurs piyo
MyAclSampleService.java
package sample.spring.security.service;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.acls.domain.GrantedAuthoritySid;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.domain.PrincipalSid;
import org.springframework.security.acls.model.AlreadyExistsException;
import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.MutableAclService;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.transaction.annotation.Transactional;
import sample.spring.security.domain.Foo;
@Transactional
public class MyAclSampleService {
private MutableAclService aclService;
public MyAclSampleService(MutableAclService aclService) {
this.aclService = aclService;
}
public void addPermission() {
ObjectIdentity objectIdentity = new ObjectIdentityImpl(Foo.class, 10L);
MutableAcl acl = (MutableAcl) this.aclService.readAclById(objectIdentity);
acl.insertAce(
acl.getEntries().size(),
BasePermission.READ,
new GrantedAuthoritySid(new SimpleGrantedAuthority("test")),
true
);
this.aclService.updateAcl(acl);
}
}
Foo
avec ʻid = 10 et ajout d'autorisations avec ʻinsertAce ()
MyAclServlet.java
package sample.spring.security.servlet;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.acls.model.NotFoundException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import sample.spring.security.service.MyAclSampleService;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@WebServlet("/acl")
public class MyAclServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
MyAclSampleService service = this.findServiceBean(req, MyAclSampleService.class);
this.printPrincipal();
this.printTables(req);
try {
System.out.println("service.addPermission()");
service.addPermission();
this.printTables(req);
} catch (AccessDeniedException | NotFoundException e) {
System.out.println("e.class = " + e.getClass() + ", message = " + e.getMessage());
}
}
...
}
de
MyAclSampleService, affiche à nouveau l'état de la base de données. --Si une exception se produit dans ʻaddPermission ()
, cette information est sortie.** Lors de l'accès en tant qu'utilisateur hoge **
Sortie de la console du serveur
★ Informations utilisateur
name=hoge
authorities=
★ État du tableau avant mise à jour
[ACL_SID]
{ID=9, PRINCIPAL=true, SID=hoge}
{ID=19, PRINCIPAL=true, SID=admin}
[ACL_CLASS]
{ID=100, CLASS=sample.spring.security.domain.Foo}
[ACL_OBJECT_IDENTITY]
{ID=1000, OBJECT_ID_CLASS=100, OBJECT_ID_IDENTITY=10, PARENT_OBJECT=null, OWNER_SID=9, ENTRIES_INHERITING=true}
[ACL_ENTRY]
{ID=10000, ACL_OBJECT_IDENTITY=1000, ACE_ORDER=0, SID=19, MASK=16, GRANTING=true, AUDIT_SUCCESS=false, AUDIT_FAILURE=false}
★ Exécution de la méthode
service.addPermission()
★ État du tableau après mise à jour
[ACL_SID]
{ID=9, PRINCIPAL=true, SID=hoge}
{ID=19, PRINCIPAL=true, SID=admin}
{ID=20, PRINCIPAL=false, SID=test}
[ACL_CLASS]
{ID=100, CLASS=sample.spring.security.domain.Foo}
[ACL_OBJECT_IDENTITY]
{ID=1000, OBJECT_ID_CLASS=100, OBJECT_ID_IDENTITY=10, PARENT_OBJECT=null, OWNER_SID=9, ENTRIES_INHERITING=true}
[ACL_ENTRY]
{ID=10001, ACL_OBJECT_IDENTITY=1000, ACE_ORDER=0, SID=19, MASK=16, GRANTING=true, AUDIT_SUCCESS=false, AUDIT_FAILURE=false}
{ID=10002, ACL_OBJECT_IDENTITY=1000, ACE_ORDER=1, SID=20, MASK=1, GRANTING=true, AUDIT_SUCCESS=false, AUDIT_FAILURE=false}
** Lors de l'accès en tant qu'utilisateur fuga **
Sortie de la console du serveur
★ Informations utilisateur
name=fuga
authorities=
★ État du tableau avant mise à jour
[ACL_SID]
{ID=9, PRINCIPAL=true, SID=hoge}
{ID=19, PRINCIPAL=true, SID=admin}
[ACL_CLASS]
{ID=100, CLASS=sample.spring.security.domain.Foo}
[ACL_OBJECT_IDENTITY]
{ID=1000, OBJECT_ID_CLASS=100, OBJECT_ID_IDENTITY=10, PARENT_OBJECT=null, OWNER_SID=9, ENTRIES_INHERITING=true}
[ACL_ENTRY]
{ID=10000, ACL_OBJECT_IDENTITY=1000, ACE_ORDER=0, SID=19, MASK=16, GRANTING=true, AUDIT_SUCCESS=false, AUDIT_FAILURE=false}
★ Exécution de la méthode
service.addPermission()
★ Informations d'erreur
e.class = class org.springframework.security.acls.model.NotFoundException, message = Unable to locate a matching ACE for passed permissions and SIDs
NotFoundException
) a été levée** Lors de l'accès en tant qu'utilisateur piyo **
Sortie de la console du serveur
★ Informations utilisateur
name=piyo
authorities=PERMISSION_MANAGER
★ État du tableau avant mise à jour
[ACL_SID]
{ID=9, PRINCIPAL=true, SID=hoge}
{ID=19, PRINCIPAL=true, SID=admin}
[ACL_CLASS]
{ID=100, CLASS=sample.spring.security.domain.Foo}
[ACL_OBJECT_IDENTITY]
{ID=1000, OBJECT_ID_CLASS=100, OBJECT_ID_IDENTITY=10, PARENT_OBJECT=null, OWNER_SID=9, ENTRIES_INHERITING=true}
[ACL_ENTRY]
{ID=10000, ACL_OBJECT_IDENTITY=1000, ACE_ORDER=0, SID=19, MASK=16, GRANTING=true, AUDIT_SUCCESS=false, AUDIT_FAILURE=false}
★ Exécution de la méthode
service.addPermission()
★ État du tableau après mise à jour
[ACL_SID]
{ID=9, PRINCIPAL=true, SID=hoge}
{ID=19, PRINCIPAL=true, SID=admin}
{ID=20, PRINCIPAL=false, SID=test}
[ACL_CLASS]
{ID=100, CLASS=sample.spring.security.domain.Foo}
[ACL_OBJECT_IDENTITY]
{ID=1000, OBJECT_ID_CLASS=100, OBJECT_ID_IDENTITY=10, PARENT_OBJECT=null, OWNER_SID=9, ENTRIES_INHERITING=true}
[ACL_ENTRY]
{ID=10001, ACL_OBJECT_IDENTITY=1000, ACE_ORDER=0, SID=19, MASK=16, GRANTING=true, AUDIT_SUCCESS=false, AUDIT_FAILURE=false}
{ID=10002, ACL_OBJECT_IDENTITY=1000, ACE_ORDER=1, SID=20, MASK=1, GRANTING=true, AUDIT_SUCCESS=false, AUDIT_FAILURE=false}
** Lors de l'accès en tant qu'utilisateur administrateur **
Sortie de la console du serveur
★ Informations utilisateur
name=admin
authorities=
★ État du tableau avant mise à jour
[ACL_SID]
{ID=9, PRINCIPAL=true, SID=hoge}
{ID=19, PRINCIPAL=true, SID=admin}
[ACL_CLASS]
{ID=100, CLASS=sample.spring.security.domain.Foo}
[ACL_OBJECT_IDENTITY]
{ID=1000, OBJECT_ID_CLASS=100, OBJECT_ID_IDENTITY=10, PARENT_OBJECT=null, OWNER_SID=9, ENTRIES_INHERITING=true}
[ACL_ENTRY]
{ID=10000, ACL_OBJECT_IDENTITY=1000, ACE_ORDER=0, SID=19, MASK=16, GRANTING=true, AUDIT_SUCCESS=false, AUDIT_FAILURE=false}
★ Exécution de la méthode
service.addPermission()
★ État du tableau après mise à jour
[ACL_SID]
{ID=9, PRINCIPAL=true, SID=hoge}
{ID=19, PRINCIPAL=true, SID=admin}
{ID=20, PRINCIPAL=false, SID=test}
[ACL_CLASS]
{ID=100, CLASS=sample.spring.security.domain.Foo}
[ACL_OBJECT_IDENTITY]
{ID=1000, OBJECT_ID_CLASS=100, OBJECT_ID_IDENTITY=10, PARENT_OBJECT=null, OWNER_SID=9, ENTRIES_INHERITING=true}
[ACL_ENTRY]
{ID=10001, ACL_OBJECT_IDENTITY=1000, ACE_ORDER=0, SID=19, MASK=16, GRANTING=true, AUDIT_SUCCESS=false, AUDIT_FAILURE=false}
{ID=10002, ACL_OBJECT_IDENTITY=1000, ACE_ORDER=1, SID=20, MASK=1, GRANTING=true, AUDIT_SUCCESS=false, AUDIT_FAILURE=false}
Il existe trois types de mises à jour d'ACL:
--Général
Et les méthodes de mise à jour de l'ACL sont classées comme suit.
Méthode | Type de mise à jour |
---|---|
insertAce() |
Général |
updateAce() |
Général |
deleteAce() |
Général |
setParent() |
Général |
setEntriesInheriting() |
Général |
setOwner() |
Possédé |
updateAuditing() |
Audit |
Au fait, ces trois types sont définis dans l'interface ʻAclAuthorizationStrategy`.
AclAuthorizationStrategy.java
public interface AclAuthorizationStrategy {
int CHANGE_OWNERSHIP = 0;Possédé
int CHANGE_AUDITING = 1;Audit
int CHANGE_GENERAL = 2;Général
applicationContext.xml
<bean id="aclAuthorizationStrategy" class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
<constructor-arg>
<list>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="PERMISSION_MANAGER"/>
</bean>
</list>
</constructor-arg>
</bean>
--ʻGrantedAuthority passé dans le constructeur de AclAuthorizationStrategyImpl
est utilisé lors de la mise à jour de l'ACL.
Dans l'exemple ci-dessus, seule l'autorité «PERMISSION_MANAGER» est spécifiée. Dans ce cas, tous les types de mises à jour (générales, détenues, auditées) seront autorisés si vous disposez de cette autorité.
Si vous voulez contrôler "●● est requis pour la mise à jour" générale ", ▲▲ est requis pour la mise à jour" possédée "et ★★ est requis pour" audit "", comme suit. Définissez un bean dans.
applicationContext.xml
<bean id="aclAuthorizationStrategy" class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
<constructor-arg>
<list>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="PERMISSION_MANAGER_OWNERSHIP"/>
</bean>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="PERMISSION_MANAGER_AUDIT"/>
</bean>
<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
<constructor-arg value="PERMISSION_MANAGER_GENERAL"/>
</bean>
</list>
</constructor-arg>
</bean>
--Définissez le nombre de GrantedAuthority
s passés à l'argument constructeur à 3 (notez que 2 ou 4 entraîneront une erreur)
Dans l'exemple ci-dessus, une NotFoundException
a été lancée si la mise à jour a été refusée.
Ce n'est pas vrai que «NotFoundException» est toujours levé lorsqu'il n'est pas autorisé.
Si l'ACL à mettre à jour a la permission de ʻadministration définie sur "deny", ʻAccessDeniedException
est levée.
C'est en fait un ** bogue **, et dans les deux cas, il est correct de lancer ʻAccessDeniedException`.
Une recherche d'un problème sur GitHub révèle ce bogue a été soulevé. Cependant, depuis le 09 juillet 2017, ce problème reste OUVERT et ne semble pas être résolu. Il semble que ce problème ait été reconnu en 2009, il a donc été complètement négligé (sans s'y limiter, tous les problèmes liés à l'ACL ont été négligés pendant longtemps et peuvent ne pas être beaucoup entretenus. inconnue).
De plus, la vérification des autorisations pour la mise à jour de l'ACL ne fait pas référence au rôle parent lors de l'utilisation des hiérarchies de rôles [https://github.com/spring-projects/spring-security/issues] Des bogues tels que / 4186) ont été soulevés (également laissés sans surveillance pendant une longue période).
Si vous voulez utiliser cette zone de manière correcte, vous devez copier le ʻAclAuthorizationStrategyImpl existant, créer votre propre classe d'implémentation qui résout le problème, et l'utiliser à la place de ʻAclAuthorizationStrategyImpl
.
(Ou tirez-vous la demande de la version modifiée vers la famille principale)
ʻACL_OBJECT_IDENTITY` peut avoir une relation d'héritage.
Hello World
insert_acl_tables.sql
INSERT INTO ACL_CLASS (ID, CLASS)
VALUES (100, 'sample.spring.security.domain.Foo');
INSERT INTO ACL_SID (ID, PRINCIPAL, SID)
VALUES (9, true, 'hoge');
INSERT INTO ACL_SID (ID, PRINCIPAL, SID)
VALUES (98, false, 'READONLY');
INSERT INTO ACL_OBJECT_IDENTITY (ID, OBJECT_ID_CLASS, OBJECT_ID_IDENTITY, PARENT_OBJECT, OWNER_SID, ENTRIES_INHERITING)
VALUES (1000, 100, 44, NULL, 9, false);
INSERT INTO ACL_OBJECT_IDENTITY (ID, OBJECT_ID_CLASS, OBJECT_ID_IDENTITY, PARENT_OBJECT, OWNER_SID, ENTRIES_INHERITING)
VALUES (1001, 100, 45, NULL, 9, false);
INSERT INTO ACL_OBJECT_IDENTITY (ID, OBJECT_ID_CLASS, OBJECT_ID_IDENTITY, PARENT_OBJECT, OWNER_SID, ENTRIES_INHERITING)
VALUES (1002, 100, 46, 1000, 9, false);
INSERT INTO ACL_OBJECT_IDENTITY (ID, OBJECT_ID_CLASS, OBJECT_ID_IDENTITY, PARENT_OBJECT, OWNER_SID, ENTRIES_INHERITING)
VALUES (1003, 100, 47, 1000, 9, true);
INSERT INTO ACL_ENTRY (ID, ACL_OBJECT_IDENTITY, ACE_ORDER, SID, MASK, GRANTING, AUDIT_SUCCESS, AUDIT_FAILURE)
VALUES (10, 1000, 0, 98, 1, true, false, false);
--Définir ʻACL_OBJECT_IDENTITY de ʻid = 44 ... 47
--Seulement ʻid = 44 a l'autorisation de lecture sur le privilège
READONLY. --ʻId = 45
ne spécifie aucun objet parent, etc.
--ʻId = 46spécifie uniquement l'ID de l'objet parent avec
PARENT_OBJECT (ʻENTRIES_INHERITING
est false
)
--ʻId = 47 définit ʻENTRIES_INHERITING
sur true
après avoir spécifié l'objet parent.
MyAclSampleService.java
package sample.spring.security.service;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import sample.spring.security.domain.Foo;
@Transactional
public class MyAclSampleService {
@PreAuthorize("hasPermission(#foo, read)")
public void read(Foo foo) {
System.out.println("read(" + foo + ")");
}
}
MyAclServlet.java
package sample.spring.security.servlet;
...
import sample.spring.security.domain.Foo;
import sample.spring.security.service.MyAclSampleService;
@WebServlet("/acl")
public class MyAclServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.printPrincipal();
this.printTables(req);
this.callServiceLogic(req, 44L);
this.callServiceLogic(req, 45L);
this.callServiceLogic(req, 46L);
this.callServiceLogic(req, 47L);
}
private void callServiceLogic(HttpServletRequest req, long id) {
try {
System.out.println("id=" + id);
MyAclSampleService service = this.findServiceBean(req);
Foo foo = new Foo(id);
service.read(foo);
} catch (AccessDeniedException e) {
System.out.println("AccessDeniedException : " + e.getMessage());
}
}
...
}
--Créez un objet Foo
avec ʻid = 44 ... 47 et exécutez la méthode
read () de
MyAclSampleService`
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
...>
...
<sec:authentication-manager>
<sec:authentication-provider>
<sec:user-service>
<sec:user name="foo" password="foo" authorities="READONLY" />
</sec:user-service>
</sec:authentication-provider>
</sec:authentication-manager>
</beans>
READONLY
à l'utilisateur foo
Connectez-vous en tant qu'utilisateur foo
et accédez à / acl
.
Sortie de la console du serveur
name=foo
authorities=READONLY
[ACL_SID]
{ID=9, PRINCIPAL=true, SID=hoge}
{ID=98, PRINCIPAL=false, SID=READONLY}
[ACL_CLASS]
{ID=100, CLASS=sample.spring.security.domain.Foo}
[ACL_OBJECT_IDENTITY]
{ID=1000, OBJECT_ID_CLASS=100, OBJECT_ID_IDENTITY=44, PARENT_OBJECT=null, OWNER_SID=9, ENTRIES_INHERITING=false}
{ID=1001, OBJECT_ID_CLASS=100, OBJECT_ID_IDENTITY=45, PARENT_OBJECT=null, OWNER_SID=9, ENTRIES_INHERITING=false}
{ID=1002, OBJECT_ID_CLASS=100, OBJECT_ID_IDENTITY=46, PARENT_OBJECT=1000, OWNER_SID=9, ENTRIES_INHERITING=false}
{ID=1003, OBJECT_ID_CLASS=100, OBJECT_ID_IDENTITY=47, PARENT_OBJECT=1000, OWNER_SID=9, ENTRIES_INHERITING=true}
[ACL_ENTRY]
{ID=10, ACL_OBJECT_IDENTITY=1000, ACE_ORDER=0, SID=98, MASK=1, GRANTING=true, AUDIT_SUCCESS=false, AUDIT_FAILURE=false}
id=44
read(Foo{id=44})
id=45
AccessDeniedException : Access is denied
id=46
AccessDeniedException : Access is denied
id=47
read(Foo{id=47})
--Seulement ʻid = 44, 47 peut exécuter la méthode, ʻid = 45, 46
est rejeté
insert_acl_tables.sql
...
INSERT INTO ACL_OBJECT_IDENTITY (ID, OBJECT_ID_CLASS, OBJECT_ID_IDENTITY, PARENT_OBJECT, OWNER_SID, ENTRIES_INHERITING)
VALUES (1000, 100, 44, NULL, 9, false);
INSERT INTO ACL_OBJECT_IDENTITY (ID, OBJECT_ID_CLASS, OBJECT_ID_IDENTITY, PARENT_OBJECT, OWNER_SID, ENTRIES_INHERITING)
VALUES (1001, 100, 45, NULL, 9, false);
INSERT INTO ACL_OBJECT_IDENTITY (ID, OBJECT_ID_CLASS, OBJECT_ID_IDENTITY, PARENT_OBJECT, OWNER_SID, ENTRIES_INHERITING)
VALUES (1002, 100, 46, 1000, 9, false);
INSERT INTO ACL_OBJECT_IDENTITY (ID, OBJECT_ID_CLASS, OBJECT_ID_IDENTITY, PARENT_OBJECT, OWNER_SID, ENTRIES_INHERITING)
VALUES (1003, 100, 47, 1000, 9, true);
--Pour donner l'héritage des autorisations, ajoutez les deux paramètres suivants à ʻACL_OBJECT_IDENTITY --Définissez
PARENT_OBJECT sur ʻID
du parent ʻACL_OBJECT_IDENTITY --Réglez
true à ʻENTRIES_INHERITING
de ʻACL_OBJECT_IDENTITY
peut être enregistré même si ce n'est pas un ʻid existant. --Si vous enregistrez ʻACL_OBJECT_IDENTITY
avec une valeur impossible telle que ʻOBJECT_IDENTITY = -1 et que d'autres ʻACL_OBJECT_IDENTITY
normaux héritent de cette valeur par défaut ʻACL_OBJECT_IDENTITY, la permission par défaut sera réalisable ,Cependant, si l'héritage est superposé en plusieurs couches, je pense qu'il sera difficile de spécifier "toutes les autorisations définies dans cet ʻACL_OBJECT_IDENTITY
" avec SQL seul (la valeur maximale de la couche est fixée). Si tel est le cas, est-ce que vous pouvez faire `` GAUCHE '' pour ce numéro?)
«Je pense qu'il est plus sûr de garder la hiérarchie aussi petite que possible.MyAclSampleService.java
package sample.spring.security.service;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.acls.domain.GrantedAuthoritySid;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.MutableAclService;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.transaction.annotation.Transactional;
import sample.spring.security.domain.Foo;
@Transactional
public class MyAclSampleService {
private MutableAclService aclService;
public MyAclSampleService(MutableAclService aclService) {
this.aclService = aclService;
}
public void init() {
ObjectIdentityImpl parentId = new ObjectIdentityImpl(Foo.class, 44L);
MutableAcl parentAcl = this.aclService.createAcl(parentId);
parentAcl.insertAce(
parentAcl.getEntries().size(),
BasePermission.READ,
new GrantedAuthoritySid(new SimpleGrantedAuthority("READONLY")),
true
);
this.aclService.updateAcl(parentAcl);
ObjectIdentityImpl childId = new ObjectIdentityImpl(Foo.class, 45L);
MutableAcl childAcl = this.aclService.createAcl(childId);
childAcl.setParent(parentAcl);
this.aclService.updateAcl(childAcl);
}
}
python
package sample.spring.security.servlet;
...
@WebServlet("/acl")
public class MyAclServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
MyAclSampleService service = this.findServiceBean(req);
service.init();
this.printTables(req);
}
...
}
Accéder à / acl
Sortie du journal du serveur
[ACL_SID]
{ID=1, PRINCIPAL=true, SID=foo}
{ID=2, PRINCIPAL=false, SID=READONLY}
[ACL_CLASS]
{ID=1, CLASS=sample.spring.security.domain.Foo}
[ACL_OBJECT_IDENTITY]
{ID=1, OBJECT_ID_CLASS=1, OBJECT_ID_IDENTITY=44, PARENT_OBJECT=null, OWNER_SID=1, ENTRIES_INHERITING=true}
{ID=2, OBJECT_ID_CLASS=1, OBJECT_ID_IDENTITY=45, PARENT_OBJECT=1, OWNER_SID=1, ENTRIES_INHERITING=true}
[ACL_ENTRY]
{ID=1, ACL_OBJECT_IDENTITY=1, ACE_ORDER=0, SID=2, MASK=1, GRANTING=true, AUDIT_SUCCESS=false, AUDIT_FAILURE=false}
MyAclSampleService.java
public void init() {
ObjectIdentityImpl parentId = new ObjectIdentityImpl(Foo.class, 44L);
MutableAcl parentAcl = this.aclService.createAcl(parentId);
parentAcl.insertAce(
parentAcl.getEntries().size(),
BasePermission.READ,
new GrantedAuthoritySid(new SimpleGrantedAuthority("READONLY")),
true
);
this.aclService.updateAcl(parentAcl);
ObjectIdentityImpl childId = new ObjectIdentityImpl(Foo.class, 45L);
MutableAcl childAcl = this.aclService.createAcl(childId);
childAcl.setParent(parentAcl); //★ Définissez les parents ici
this.aclService.updateAcl(childAcl);
}
setParent ()
de MutableAcl
.
--ʻENTRIES_INHERITINGprend la valeur par défaut
true quand une nouvelle ACL est créée, il n'est donc pas nécessaire de la spécifier lors de la création d'une nouvelle ACL (elle peut être définie avec la méthode
setEntriesInheriting ()`)Il existe un mécanisme pour afficher les informations sous forme de journal d'audit lorsque l'autorisation est accordée ou refusée.
Hello World
insert_acl_tables.sql
INSERT INTO ACL_CLASS (ID, CLASS)
VALUES (100, 'sample.spring.security.domain.Foo');
INSERT INTO ACL_SID (ID, PRINCIPAL, SID)
VALUES (9, true, 'hoge');
INSERT INTO ACL_SID (ID, PRINCIPAL, SID)
VALUES (98, false, 'READONLY');
INSERT INTO ACL_OBJECT_IDENTITY (ID, OBJECT_ID_CLASS, OBJECT_ID_IDENTITY, PARENT_OBJECT, OWNER_SID, ENTRIES_INHERITING)
VALUES (999, 100, 44, NULL, 9, false);
INSERT INTO ACL_ENTRY (ID, ACL_OBJECT_IDENTITY, ACE_ORDER, SID, MASK, GRANTING, AUDIT_SUCCESS, AUDIT_FAILURE)
VALUES (10, 999, 0, 98, 1, true, true, false);
INSERT INTO ACL_ENTRY (ID, ACL_OBJECT_IDENTITY, ACE_ORDER, SID, MASK, GRANTING, AUDIT_SUCCESS, AUDIT_FAILURE)
VALUES (11, 999, 1, 98, 2, false, false, true);
--Pour ʻid = 44de
Foo, définissez les autorisations" accorder
lecture" et "refuser
écrire" pour le privilège
READONLY. --ʻACL_ENTRY
de "Grant read
" change ʻAUDIT_SUCCESS en
true --ʻACL_ENTRY
dans "Reject write
"définit ʻAUDIT_FAILURE sur
true`
MyAclSampleService.java
package sample.spring.security.service;
import org.springframework.security.access.prepost.PreAuthorize;
import sample.spring.security.domain.Foo;
public class MyAclSampleService {
@PreAuthorize("hasPermission(#foo, read)")
public void read(Foo foo) {
System.out.println(foo);
}
@PreAuthorize("hasPermission(#foo, write)")
public void write(Foo foo) {
System.out.println(foo);
}
}
MyAclServlet.java
package sample.spring.security.servlet;
...
@WebServlet("/acl")
public class MyAclServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
MyAclSampleService service = this.findServiceBean(req);
Foo foo = new Foo(44L);
try {
System.out.println("service.read()");
service.read(foo);
System.out.println("service.write()");
service.write(foo);
} catch (AccessDeniedException e) {
System.out.println(e.getMessage());
}
}
...
}
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
...>
...
<bean id="permissionGrantingStrategy" class="org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy">
<constructor-arg>
<bean class="org.springframework.security.acls.domain.ConsoleAuditLogger" />
</constructor-arg>
</bean>
...
<sec:authentication-manager>
<sec:authentication-provider>
<sec:user-service>
<sec:user name="foo" password="foo" authorities="READONLY" />
</sec:user-service>
</sec:authentication-provider>
</sec:authentication-manager>
</beans>
Connectez-vous en tant qu'utilisateur foo
et accédez à / acl
Sortie de la console du serveur
service.read()
GRANTED due to ACE: AccessControlEntryImpl[id: 10; granting: true; sid: GrantedAuthoritySid[READONLY]; permission: BasePermission[...............................R=1]; auditSuccess: true; auditFailure: false]
Foo{id=44}
service.write()
DENIED due to ACE: AccessControlEntryImpl[id: 11; granting: false; sid: GrantedAuthoritySid[READONLY]; permission: BasePermission[..............................W.=2]; auditSuccess: false; auditFailure: true]
Access is denied
insert_acl_tables.sql
INSERT INTO ACL_ENTRY (ID, ACL_OBJECT_IDENTITY, ACE_ORDER, SID, MASK, GRANTING, AUDIT_SUCCESS, AUDIT_FAILURE)
VALUES (10, 999, 0, 98, 1, true, true, false);
INSERT INTO ACL_ENTRY (ID, ACL_OBJECT_IDENTITY, ACE_ORDER, SID, MASK, GRANTING, AUDIT_SUCCESS, AUDIT_FAILURE)
VALUES (11, 999, 1, 98, 2, false, false, true);
ou ʻAUDIT_FAILURE
de ʻACL_ENTRY sur
true`. est ʻa vrai
, un journal est produit lorsque l'octroi de l'autorisation est déterminé.
--Si ʻAUDIT_FAILURE est ʻa vrai
, un journal est produit lorsque le refus d'autorisation est déterminé.applicationContext.xml
<bean id="permissionGrantingStrategy" class="org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy">
<constructor-arg>
<bean class="org.springframework.security.acls.domain.ConsoleAuditLogger" />
</constructor-arg>
</bean>
--La sortie du journal d'audit est effectuée par une classe qui implémente l'interface ʻAuditLogger. --ʻAuditLogger
est défini sur DefaultPermissionGrantingStrategy
--ʻLa classe ConsoleAuditLogger
, qui est fournie en standard comme implémentation d'AuditLogger`, envoie le journal à la sortie standard.
L'implémentation de ConsoleAuditLogger
ressemble à ceci:
ConsoleAuditLogger.java
package org.springframework.security.acls.domain;
import org.springframework.security.acls.model.AccessControlEntry;
import org.springframework.security.acls.model.AuditableAccessControlEntry;
import org.springframework.util.Assert;
public class ConsoleAuditLogger implements AuditLogger {
public void logIfNeeded(boolean granted, AccessControlEntry ace) {
Assert.notNull(ace, "AccessControlEntry required");
if (ace instanceof AuditableAccessControlEntry) {
AuditableAccessControlEntry auditableAce = (AuditableAccessControlEntry) ace;
if (granted && auditableAce.isAuditSuccess()) {
System.out.println("GRANTED due to ACE: " + ace);
}
else if (!granted && auditableAce.isAuditFailure()) {
System.out.println("DENIED due to ACE: " + ace);
}
}
}
}
définit la méthode
logIfNeeded (boolean, AccessControlEntry)`.
--Le premier argument reçoit un indicateur, que l'autorisation ait été accordée ou refusée. qui contient les informations d'autorisation. --Pour obtenir le paramètre (ʻAUDIT_SUCCESS
, ʻAUDIT_FAILURE) indiquant s'il faut sortir le journal d'audit, utilisez la méthode ʻisAuditSuccess ()
ou ʻisAuditFailure () de ʻAuditableAccessControlEntry
(Argument ʻAccessControlEntry ". Vous devez lancer `)import org.springframework.security.acls.model.AuditableAcl;
...
ObjectIdentityImpl objectIdentity = new ObjectIdentityImpl(Foo.class, 44L);
AuditableAcl acl = (AuditableAcl) this.aclService.readAclById(objectIdentity);
acl.updateAuditing(0, true, false);
this.aclService.updateAcl(acl);
et ʻAUDIT_FAILURE
, utilisez la méthode ʻupdateAuditing (int, boolean, boolean) de ʻAuditableAcl
.Par défaut, seules cinq permissions sont disponibles: read
, write
, create
, delete
et ʻadministration`, mais vous pouvez définir des permissions supplémentaires de votre choix.
Essayez de faire 32
( 100000
en notation binaire).
MyPermission.java
package sample.spring.security.acl;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.acls.model.Permission;
public class MyPermission extends BasePermission {
public static final Permission HOGE = new MyPermission(0b100000, 'H');
private MyPermission(int mask, char code) {
super(mask, code);
}
}
--Créez votre propre classe Permission
en héritant de BasePermission
--Créez une constante appelée «HOGE», définissez le masque sur «0b100000» («32» en décimal) et définissez le code sur «H» pour définir l'instance.
insert_acl_tables.sql
INSERT INTO ACL_CLASS (ID, CLASS)
VALUES (100, 'sample.spring.security.domain.Foo');
INSERT INTO ACL_SID (ID, PRINCIPAL, SID)
VALUES (9, true, 'hoge');
INSERT INTO ACL_SID (ID, PRINCIPAL, SID)
VALUES (98, false, 'READONLY');
INSERT INTO ACL_SID (ID, PRINCIPAL, SID)
VALUES (99, false, 'HOGE');
INSERT INTO ACL_OBJECT_IDENTITY (ID, OBJECT_ID_CLASS, OBJECT_ID_IDENTITY, PARENT_OBJECT, OWNER_SID, ENTRIES_INHERITING)
VALUES (999, 100, 44, NULL, 9, false);
INSERT INTO ACL_ENTRY (ID, ACL_OBJECT_IDENTITY, ACE_ORDER, SID, MASK, GRANTING, AUDIT_SUCCESS, AUDIT_FAILURE)
VALUES (10, 999, 0, 98, 1, true, false, false);
INSERT INTO ACL_ENTRY (ID, ACL_OBJECT_IDENTITY, ACE_ORDER, SID, MASK, GRANTING, AUDIT_SUCCESS, AUDIT_FAILURE)
VALUES (11, 999, 1, 99, 32, true, false, false);
32
( HOGE
défini dans MyPermission
) à l'autorité HOGE
MyAclSampleService.java
package sample.spring.security.service;
import org.springframework.security.access.prepost.PreAuthorize;
import sample.spring.security.domain.Foo;
public class MyAclSampleService {
@PreAuthorize("hasPermission(#foo, read)")
public void read(Foo foo) {
System.out.println(foo);
}
@PreAuthorize("hasPermission(#foo, 'hoge')")
public void hoge(Foo foo) {
System.out.println(foo);
}
}
--Vérifiez les autorisations avec read
et hoge
respectivement
MyAclServlet.java
package sample.spring.security.servlet;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import sample.spring.security.domain.Foo;
import sample.spring.security.service.MyAclSampleService;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@WebServlet("/acl")
public class MyAclServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
MyAclSampleService service = this.findServiceBean(req);
Foo foo = new Foo(44L);
this.callMethod("read", () -> service.read(foo));
this.callMethod("hoge", () -> service.hoge(foo));
}
private void callMethod(String method, Runnable runnable) {
try {
System.out.println(method);
runnable.run();
} catch (AccessDeniedException e) {
System.out.println(e.getMessage());
}
}
...
}
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:sec="http://www.springframework.org/schema/security"
...>
...
<bean id="permissionFactory" class="org.springframework.security.acls.domain.DefaultPermissionFactory">
<constructor-arg value="sample.spring.security.acl.MyPermission" />
</bean>
<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<property name="permissionEvaluator">
<bean class="org.springframework.security.acls.AclPermissionEvaluator">
<constructor-arg ref="aclService" />
<property name="permissionFactory" ref="permissionFactory" /> ★
</bean>
</property>
</bean>
<bean id="lookupStrategy" class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
<constructor-arg ref="dataSource" />
<constructor-arg ref="aclCache" />
<constructor-arg ref="aclAuthorizationStrategy" />
<constructor-arg ref="permissionGrantingStrategy" />
<property name="permissionFactory" ref="permissionFactory" /> ★
</bean>
...
<sec:authentication-manager>
<sec:authentication-provider>
<sec:user-service>
<sec:user name="foo" password="foo" authorities="READONLY" />
<sec:user name="bar" password="bar" authorities="HOGE" />
</sec:user-service>
</sec:authentication-provider>
</sec:authentication-manager>
</beans>
--Définissez DefaultPermissionFactory
comme un bean
--Spécifiez l'objet Class
de votre proprePermission
( MyPermission
) dans l'argument du constructeur
--Définissez le Bean de DefaultPermissionFactory
sur ʻAclPermissionEvaluator et
BasicLookupStrategy` comme propriétés, respectivement.
Connectez-vous en tant qu'utilisateur foo
et accédez à / acl
Sortie de la console
read
Foo{id=44}
hoge
Access is denied
Connectez-vous en tant qu'utilisateur bar
et accédez à / acl
Sortie de la console
read
Access is denied
hoge
Foo{id=44}
MyPermission.java
package sample.spring.security.acl;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.acls.model.Permission;
public class MyPermission extends BasePermission {
public static final Permission HOGE = new MyPermission(0b100000, 'H');
private MyPermission(int mask, char code) {
super(mask, code);
}
}
--Si vous voulez définir vos propres permissions, créez une classe qui hérite de BasePermission
et définissez les permissions que vous voulez ajouter avec des constantes.
hasPermission ()
.applicationContext.xml
<bean id="permissionFactory" class="org.springframework.security.acls.domain.DefaultPermissionFactory">
<constructor-arg value="sample.spring.security.acl.MyPermission" />
</bean>
<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<property name="permissionEvaluator">
<bean class="org.springframework.security.acls.AclPermissionEvaluator">
<constructor-arg ref="aclService" />
<property name="permissionFactory" ref="permissionFactory" />
</bean>
</property>
</bean>
<bean id="lookupStrategy" class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
<constructor-arg ref="dataSource" />
<constructor-arg ref="aclCache" />
<constructor-arg ref="aclAuthorizationStrategy" />
<constructor-arg ref="permissionGrantingStrategy" />
<property name="permissionFactory" ref="permissionFactory" />
</bean>
--Si vous ne faites rien, la classe d'autorisation utilisera BasePermission
DefaultPermissionFactory
, qui est la classe d'implémentation de l'interface PermissionFactory
.
--Spécifiez l'objet Class
de la classe d'autorisation que vous souhaitez utiliser dans l'argument constructeur de cette classeDefaultPermissionFactory
sont acquises par réflexion.PermissionFactory
est utilisé dans les classes ʻAclPermissionEvaluator et
BasicLookupStrategy, remplacez leurs propriétés
permissionFactory`.MyAclSampleService.java
@PreAuthorize("hasPermission(#foo, 'hoge')")
public void hoge(Foo foo) {
System.out.println(foo);
}
SecurityExpressionRoot
.hoge
), et sinon, il est vérifié dans toutes les lettres majuscules ( HOGE
).Recommended Posts