or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

acl-services.mdcaching-performance.mdconfiguration.mddomain-model.mdindex.mdpermission-evaluation.mdstrategy-interfaces.md

caching-performance.mddocs/

0

# Caching & Performance Optimization

1

2

Spring Security ACL includes sophisticated caching and performance optimization features to ensure efficient permission checking even with complex ACL hierarchies and large datasets.

3

4

## Overview

5

6

ACL performance optimization includes:

7

8

- **`AclCache`** - Core caching interface for ACL data

9

- **`SpringCacheBasedAclCache`** - Integration with Spring's caching framework

10

- **`AclPermissionCacheOptimizer`** - Batch loading for collection filtering

11

- **Lookup Strategy Optimization** - SQL query customization

12

- **SID Filtering** - Reduce data transfer by loading only relevant entries

13

14

## AclCache Interface

15

16

The `AclCache` interface provides caching abstraction for ACL data:

17

18

```java { .api }

19

package org.springframework.security.acls.model;

20

21

public interface AclCache {

22

23

// Clear entire cache

24

void clearCache();

25

26

// Remove specific ACL from cache

27

void evictFromCache(ObjectIdentity objectIdentity);

28

29

// Remove ACL for specific SIDs from cache

30

void evictFromCache(Serializable pk);

31

32

// Retrieve ACL from cache

33

MutableAcl getFromCache(ObjectIdentity objectIdentity);

34

35

// Retrieve ACL by primary key from cache

36

MutableAcl getFromCache(Serializable pk);

37

38

// Store ACL in cache

39

void putInCache(MutableAcl acl);

40

}

41

```

42

43

## SpringCacheBasedAclCache

44

45

Production-ready cache implementation using Spring's caching framework:

46

47

```java { .api }

48

package org.springframework.security.acls.domain;

49

50

public class SpringCacheBasedAclCache implements AclCache {

51

52

public SpringCacheBasedAclCache(

53

Cache cache,

54

PermissionGrantingStrategy permissionGrantingStrategy,

55

AclAuthorizationStrategy aclAuthorizationStrategy

56

);

57

58

// Cache configuration methods

59

public void clearCache();

60

public void evictFromCache(ObjectIdentity objectIdentity);

61

public void evictFromCache(Serializable pk);

62

public MutableAcl getFromCache(ObjectIdentity objectIdentity);

63

public MutableAcl getFromCache(Serializable pk);

64

public void putInCache(MutableAcl acl);

65

}

66

```

67

68

### Basic Cache Configuration

69

70

```java { .api }

71

@Configuration

72

@EnableCaching

73

public class AclCacheConfig {

74

75

@Bean

76

public AclCache aclCache() {

77

return new SpringCacheBasedAclCache(

78

cacheManager().getCache("aclCache"),

79

permissionGrantingStrategy(),

80

aclAuthorizationStrategy()

81

);

82

}

83

84

@Bean

85

public CacheManager cacheManager() {

86

ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager("aclCache");

87

return cacheManager;

88

}

89

90

@Bean

91

public PermissionGrantingStrategy permissionGrantingStrategy() {

92

return new DefaultPermissionGrantingStrategy(auditLogger());

93

}

94

95

@Bean

96

public AclAuthorizationStrategy aclAuthorizationStrategy() {

97

return new AclAuthorizationStrategyImpl(

98

new SimpleGrantedAuthority("ROLE_ADMIN")

99

);

100

}

101

}

102

```

103

104

### Advanced Cache Configuration

105

106

```java { .api }

107

@Configuration

108

@EnableCaching

109

public class AdvancedAclCacheConfig {

110

111

@Bean

112

public CacheManager cacheManager() {

113

CaffeineCacheManager cacheManager = new CaffeineCacheManager("aclCache");

114

cacheManager.setCaffeine(Caffeine.newBuilder()

115

.maximumSize(10000) // Limit cache size

116

.expireAfterWrite(Duration.ofMinutes(30)) // TTL for entries

117

.expireAfterAccess(Duration.ofMinutes(10)) // Idle timeout

118

.recordStats() // Enable metrics

119

.removalListener((key, value, cause) -> {

120

log.debug("Evicted ACL cache entry: key={}, cause={}", key, cause);

121

}));

122

return cacheManager;

123

}

124

125

@Bean

126

public AclCache aclCache() {

127

SpringCacheBasedAclCache cache = new SpringCacheBasedAclCache(

128

cacheManager().getCache("aclCache"),

129

permissionGrantingStrategy(),

130

aclAuthorizationStrategy()

131

);

132

return cache;

133

}

134

}

135

```

136

137

## AclPermissionCacheOptimizer

138

139

Optimizes permission checking for collections by batching ACL lookups:

140

141

```java { .api }

142

package org.springframework.security.acls;

143

144

public class AclPermissionCacheOptimizer implements PermissionCacheOptimizer {

145

146

private final AclService aclService;

147

private final ObjectIdentityRetrievalStrategy objectIdentityRetrievalStrategy;

148

private final SidRetrievalStrategy sidRetrievalStrategy;

149

150

public AclPermissionCacheOptimizer(AclService aclService);

151

152

// Batch load ACLs for a collection of objects

153

@Override

154

public void cachePermissionsFor(Authentication authentication,

155

Collection<?> objects);

156

}

157

```

158

159

### Using AclPermissionCacheOptimizer

160

161

```java { .api }

162

@Configuration

163

@EnableGlobalMethodSecurity(prePostEnabled = true)

164

public class MethodSecurityConfig {

165

166

@Bean

167

public PermissionEvaluator permissionEvaluator(AclService aclService) {

168

return new AclPermissionEvaluator(aclService);

169

}

170

171

@Bean

172

public PermissionCacheOptimizer permissionCacheOptimizer(AclService aclService) {

173

return new AclPermissionCacheOptimizer(aclService);

174

}

175

}

176

177

// Usage in service methods

178

@Service

179

public class DocumentService {

180

181

@Autowired

182

private PermissionCacheOptimizer cacheOptimizer;

183

184

@PostFilter("hasPermission(filterObject, 'READ')")

185

public List<Document> getAllDocuments(Authentication auth) {

186

List<Document> documents = documentRepository.findAll();

187

188

// Pre-load permissions for all documents in a single batch query

189

cacheOptimizer.cachePermissionsFor(auth, documents);

190

191

return documents; // PostFilter will use cached data

192

}

193

}

194

```

195

196

## Performance Optimization Strategies

197

198

### 1. SID Filtering

199

200

Always provide SID lists to reduce data transfer:

201

202

```java { .api }

203

@Service

204

public class OptimizedSecurityService {

205

206

@Autowired

207

private AclService aclService;

208

209

@Autowired

210

private SidRetrievalStrategy sidRetrievalStrategy;

211

212

public boolean hasPermission(Object domainObject, Permission permission, Authentication auth) {

213

ObjectIdentity identity = new ObjectIdentityImpl(domainObject);

214

List<Sid> sids = sidRetrievalStrategy.getSids(auth);

215

216

try {

217

// Only load ACL entries for current user's SIDs

218

Acl acl = aclService.readAclById(identity, sids);

219

return acl.isGranted(Arrays.asList(permission), sids, false);

220

} catch (NotFoundException e) {

221

return false;

222

}

223

}

224

}

225

```

226

227

### 2. Batch Loading

228

229

Process multiple objects efficiently:

230

231

```java { .api }

232

public Map<Document, Boolean> checkBulkPermissions(List<Document> documents, Authentication auth) {

233

List<ObjectIdentity> identities = documents.stream()

234

.map(doc -> new ObjectIdentityImpl(Document.class, doc.getId()))

235

.collect(Collectors.toList());

236

237

List<Sid> sids = sidRetrievalStrategy.getSids(auth);

238

List<Permission> readPermission = Arrays.asList(BasePermission.READ);

239

240

try {

241

// Single batch query for all ACLs

242

Map<ObjectIdentity, Acl> acls = aclService.readAclsById(identities, sids);

243

244

return documents.stream()

245

.collect(Collectors.toMap(

246

Function.identity(),

247

doc -> {

248

ObjectIdentity identity = new ObjectIdentityImpl(Document.class, doc.getId());

249

Acl acl = acls.get(identity);

250

return acl != null && acl.isGranted(readPermission, sids, false);

251

}

252

));

253

} catch (NotFoundException e) {

254

return documents.stream()

255

.collect(Collectors.toMap(Function.identity(), doc -> false));

256

}

257

}

258

```

259

260

### 3. Custom Lookup Strategy

261

262

Optimize SQL queries for your specific database:

263

264

```java { .api }

265

@Bean

266

public LookupStrategy lookupStrategy() {

267

BasicLookupStrategy strategy = new BasicLookupStrategy(

268

dataSource(),

269

aclCache(),

270

aclAuthorizationStrategy(),

271

permissionGrantingStrategy()

272

);

273

274

// Customize SQL for better performance

275

strategy.setSelectClause(

276

"SELECT obj.object_id_identity, " +

277

"class.class, " +

278

"sid.sid, sid.principal, " +

279

"acl.entries_inheriting, acl.id as acl_id, " +

280

"acl.parent_object, acl.owner_sid, " +

281

"entry.id, entry.mask, entry.granting, " +

282

"entry.audit_success, entry.audit_failure "

283

);

284

285

// Add database-specific optimizations

286

strategy.setLookupObjectIdentitiesWhereClause("(obj.object_id_identity = ? and class.class = ?)");

287

288

return strategy;

289

}

290

```

291

292

### 4. Connection Pool Optimization

293

294

Configure database connections for ACL workloads:

295

296

```java { .api }

297

@Configuration

298

public class DataSourceConfig {

299

300

@Bean

301

public DataSource dataSource() {

302

HikariConfig config = new HikariConfig();

303

config.setJdbcUrl("jdbc:postgresql://localhost/acl_db");

304

config.setUsername("acluser");

305

config.setPassword("password");

306

307

// Optimize for ACL read-heavy workloads

308

config.setMaximumPoolSize(25);

309

config.setMinimumIdle(10);

310

config.setConnectionTimeout(20000);

311

config.setIdleTimeout(300000);

312

config.setMaxLifetime(1200000);

313

314

// Optimize for batch queries

315

config.addDataSourceProperty("cachePrepStmts", "true");

316

config.addDataSourceProperty("prepStmtCacheSize", "250");

317

config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");

318

config.addDataSourceProperty("useServerPrepStmts", "true");

319

320

return new HikariDataSource(config);

321

}

322

}

323

```

324

325

## Monitoring and Metrics

326

327

### Cache Metrics

328

329

Monitor cache performance:

330

331

```java { .api }

332

@Component

333

public class AclCacheMetrics {

334

335

private final CacheManager cacheManager;

336

private final MeterRegistry meterRegistry;

337

338

@EventListener

339

@Async

340

public void handleCacheEvictEvent(CacheEvictEvent event) {

341

meterRegistry.counter("acl.cache.evictions",

342

"cache", event.getCacheName()).increment();

343

}

344

345

@Scheduled(fixedRate = 60000) // Every minute

346

public void recordCacheStats() {

347

Cache aclCache = cacheManager.getCache("aclCache");

348

if (aclCache instanceof CaffeineCache) {

349

com.github.benmanes.caffeine.cache.Cache<Object, Object> nativeCache =

350

((CaffeineCache) aclCache).getNativeCache();

351

352

CacheStats stats = nativeCache.stats();

353

354

meterRegistry.gauge("acl.cache.size", nativeCache.estimatedSize());

355

meterRegistry.gauge("acl.cache.hit.rate", stats.hitRate());

356

meterRegistry.gauge("acl.cache.miss.rate", stats.missRate());

357

meterRegistry.gauge("acl.cache.eviction.count", stats.evictionCount());

358

}

359

}

360

}

361

```

362

363

### Performance Metrics

364

365

Track ACL operation performance:

366

367

```java { .api }

368

@Component

369

public class AclPerformanceMonitor {

370

371

private final MeterRegistry meterRegistry;

372

373

@EventListener

374

public void handleAclServiceCall(AclServiceCallEvent event) {

375

Timer.Sample sample = Timer.start(meterRegistry);

376

sample.stop(Timer.builder("acl.service.call")

377

.tag("method", event.getMethodName())

378

.tag("object.count", String.valueOf(event.getObjectCount()))

379

.register(meterRegistry));

380

}

381

}

382

```

383

384

## Best Practices

385

386

### 1. Cache Warming

387

388

Pre-populate cache with frequently accessed ACLs:

389

390

```java { .api }

391

@Component

392

public class AclCacheWarmer {

393

394

@Autowired

395

private AclService aclService;

396

397

@EventListener(ApplicationReadyEvent.class)

398

public void warmUpCache() {

399

// Load frequently accessed ACLs on startup

400

List<ObjectIdentity> frequentlyAccessed = getFrequentlyAccessedObjects();

401

402

try {

403

aclService.readAclsById(frequentlyAccessed);

404

} catch (NotFoundException e) {

405

log.warn("Some ACLs not found during cache warming", e);

406

}

407

}

408

}

409

```

410

411

### 2. Cache Invalidation Strategy

412

413

Invalidate cache appropriately when ACLs change:

414

415

```java { .api }

416

@Service

417

public class CacheAwareMutableAclService {

418

419

@Autowired

420

private MutableAclService mutableAclService;

421

422

@Autowired

423

private AclCache aclCache;

424

425

public MutableAcl updateAcl(MutableAcl acl) {

426

MutableAcl updated = mutableAclService.updateAcl(acl);

427

428

// Invalidate cache entry

429

aclCache.putInCache(updated);

430

431

// Also invalidate parent ACLs if inheritance is involved

432

if (updated.getParentAcl() != null) {

433

aclCache.evictFromCache(updated.getParentAcl().getObjectIdentity());

434

}

435

436

return updated;

437

}

438

}

439

```

440

441

### 3. Memory Management

442

443

Monitor and manage cache memory usage:

444

445

```java { .api }

446

@Configuration

447

public class AclCacheMemoryConfig {

448

449

@Bean

450

public CacheManager cacheManager() {

451

CaffeineCacheManager manager = new CaffeineCacheManager("aclCache");

452

manager.setCaffeine(Caffeine.newBuilder()

453

.maximumWeight(100_000_000) // 100MB

454

.weigher((key, value) -> {

455

// Custom weigher for ACL objects

456

if (value instanceof AclImpl) {

457

AclImpl acl = (AclImpl) value;

458

return 1000 + (acl.getEntries().size() * 100);

459

}

460

return 1000;

461

})

462

.recordStats());

463

return manager;

464

}

465

}

466

```

467

468

Proper caching and performance optimization is essential for production ACL deployments. The next step is understanding [configuration and setup](configuration.md) to integrate these performance features into your application.