Skip to content

Commit f20219d

Browse files
mixas27Rob Winch
authored and
Rob Winch
committed
Added possibility create custom Sid
1 parent fa9e799 commit f20219d

File tree

6 files changed

+132
-33
lines changed

6 files changed

+132
-33
lines changed

acl/src/main/java/org/springframework/security/acls/domain/AclAuthorizationStrategyImpl.java

+12-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ public void securityCheck(Acl acl, int changeType) {
8787
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
8888

8989
// Check if authorized by virtue of ACL ownership
90-
Sid currentUser = new PrincipalSid(authentication);
90+
Sid currentUser = createCurrentUser(authentication);
9191

9292
if (currentUser.equals(acl.getOwner())
9393
&& ((changeType == CHANGE_GENERAL) || (changeType == CHANGE_OWNERSHIP))) {
@@ -123,6 +123,17 @@ public void securityCheck(Acl acl, int changeType) {
123123
"Principal does not have required ACL permissions to perform requested operation");
124124
}
125125

126+
/**
127+
* Creates a principal-like sid from the authentication information.
128+
*
129+
* @param authentication the authentication information that can provide principal and thus the sid's id will be
130+
* dependant on the value inside
131+
* @return a sid with the ID taken from the authentication information
132+
*/
133+
protected Sid createCurrentUser(Authentication authentication) {
134+
return new PrincipalSid(authentication);
135+
}
136+
126137
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
127138
Assert.notNull(sidRetrievalStrategy, "SidRetrievalStrategy required");
128139
this.sidRetrievalStrategy = sidRetrievalStrategy;

acl/src/main/java/org/springframework/security/acls/jdbc/BasicLookupStrategy.java

+26-22
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
*
7575
* @author Ben Alex
7676
*/
77-
public final class BasicLookupStrategy implements LookupStrategy {
77+
public class BasicLookupStrategy implements LookupStrategy {
7878

7979
public final static String DEFAULT_SELECT_CLAUSE = "select acl_object_identity.object_id_identity, "
8080
+ "acl_entry.ace_order, "
@@ -256,7 +256,7 @@ public void setValues(PreparedStatement ps) throws SQLException {
256256
* should not throw {@link NotFoundException}, as a chain of {@link LookupStrategy}s may be used
257257
* to automatically create entries if required)
258258
*/
259-
public Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) {
259+
public final Map<ObjectIdentity, Acl> readAclsById(List<ObjectIdentity> objects, List<Sid> sids) {
260260
Assert.isTrue(batchSize >= 1, "BatchSize must be >= 1");
261261
Assert.notEmpty(objects, "Objects to lookup required");
262262

@@ -428,17 +428,33 @@ private AclImpl convert(Map<Serializable, Acl> inputMap, Long currentIdentity) {
428428
return result;
429429
}
430430

431+
/**
432+
* Creates a particular implementation of {@link Sid} depending on the arguments.
433+
*
434+
* @param sid the name of the sid representing its unique identifier. In typical ACL database schema it's
435+
* located in table {@code acl_sid} table, {@code sid} column.
436+
* @param isPrincipal whether it's a user or granted authority like role
437+
* @return the instance of Sid with the {@code sidName} as an identifier
438+
*/
439+
protected Sid createSid(boolean isPrincipal, String sid) {
440+
if (isPrincipal) {
441+
return new PrincipalSid(sid);
442+
} else {
443+
return new GrantedAuthoritySid(sid);
444+
}
445+
}
446+
431447
/**
432448
* Sets the {@code PermissionFactory} instance which will be used to convert loaded permission
433449
* data values to {@code Permission}s. A {@code DefaultPermissionFactory} will be used by default.
434450
*
435451
* @param permissionFactory
436452
*/
437-
public void setPermissionFactory(PermissionFactory permissionFactory) {
453+
public final void setPermissionFactory(PermissionFactory permissionFactory) {
438454
this.permissionFactory = permissionFactory;
439455
}
440456

441-
public void setBatchSize(int batchSize) {
457+
public final void setBatchSize(int batchSize) {
442458
this.batchSize = batchSize;
443459
}
444460

@@ -448,28 +464,28 @@ public void setBatchSize(int batchSize) {
448464
*
449465
* @param selectClause the select clause, which defaults to {@link #DEFAULT_SELECT_CLAUSE}.
450466
*/
451-
public void setSelectClause(String selectClause) {
467+
public final void setSelectClause(String selectClause) {
452468
this.selectClause = selectClause;
453469
}
454470

455471
/**
456472
* The SQL for the where clause used in the <tt>lookupPrimaryKey</tt> method.
457473
*/
458-
public void setLookupPrimaryKeysWhereClause(String lookupPrimaryKeysWhereClause) {
474+
public final void setLookupPrimaryKeysWhereClause(String lookupPrimaryKeysWhereClause) {
459475
this.lookupPrimaryKeysWhereClause = lookupPrimaryKeysWhereClause;
460476
}
461477

462478
/**
463479
* The SQL for the where clause used in the <tt>lookupObjectIdentities</tt> method.
464480
*/
465-
public void setLookupObjectIdentitiesWhereClause(String lookupObjectIdentitiesWhereClause) {
481+
public final void setLookupObjectIdentitiesWhereClause(String lookupObjectIdentitiesWhereClause) {
466482
this.lookupObjectIdentitiesWhereClause = lookupObjectIdentitiesWhereClause;
467483
}
468484

469485
/**
470486
* The SQL for the "order by" clause used in both queries.
471487
*/
472-
public void setOrderByClause(String orderByClause) {
488+
public final void setOrderByClause(String orderByClause) {
473489
this.orderByClause = orderByClause;
474490
}
475491

@@ -556,13 +572,7 @@ private void convertCurrentResultIntoObject(Map<Serializable, Acl> acls, ResultS
556572
}
557573

558574
boolean entriesInheriting = rs.getBoolean("entries_inheriting");
559-
Sid owner;
560-
561-
if (rs.getBoolean("acl_principal")) {
562-
owner = new PrincipalSid(rs.getString("acl_sid"));
563-
} else {
564-
owner = new GrantedAuthoritySid(rs.getString("acl_sid"));
565-
}
575+
Sid owner = createSid(rs.getBoolean("acl_principal"), rs.getString("acl_sid"));
566576

567577
acl = new AclImpl(objectIdentity, id, aclAuthorizationStrategy, grantingStrategy, parentAcl, null,
568578
entriesInheriting, owner);
@@ -574,13 +584,7 @@ private void convertCurrentResultIntoObject(Map<Serializable, Acl> acls, ResultS
574584
// It is permissible to have no ACEs in an ACL (which is detected by a null ACE_SID)
575585
if (rs.getString("ace_sid") != null) {
576586
Long aceId = new Long(rs.getLong("ace_id"));
577-
Sid recipient;
578-
579-
if (rs.getBoolean("ace_principal")) {
580-
recipient = new PrincipalSid(rs.getString("ace_sid"));
581-
} else {
582-
recipient = new GrantedAuthoritySid(rs.getString("ace_sid"));
583-
}
587+
Sid recipient = createSid(rs.getBoolean("ace_principal"), rs.getString("ace_sid"));
584588

585589
int mask = rs.getInt("mask");
586590
Permission permission = permissionFactory.buildFromMask(mask);

acl/src/main/java/org/springframework/security/acls/jdbc/JdbcMutableAclService.java

+13
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,19 @@ protected Long createOrRetrieveSidPrimaryKey(Sid sid, boolean allowCreate) {
209209
throw new IllegalArgumentException("Unsupported implementation of Sid");
210210
}
211211

212+
return createOrRetrieveSidPrimaryKey(sidName, sidIsPrincipal, allowCreate);
213+
}
214+
215+
/**
216+
* Retrieves the primary key from acl_sid, creating a new row if needed and the allowCreate property is
217+
* true.
218+
* @param sidName name of Sid to find or to create
219+
* @param sidIsPrincipal whether it's a user or granted authority like role
220+
* @param allowCreate true if creation is permitted if not found
221+
* @return the primary key or null if not found
222+
*/
223+
protected Long createOrRetrieveSidPrimaryKey(String sidName, boolean sidIsPrincipal, boolean allowCreate) {
224+
212225
List<Long> sidIds = jdbcTemplate.queryForList(selectSidPrimaryKey,
213226
new Object[] {Boolean.valueOf(sidIsPrincipal), sidName}, Long.class);
214227

acl/src/test/java/org/springframework/security/acls/jdbc/BasicLookupStrategyTests.java

+17-9
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,7 @@
99
import org.springframework.core.io.Resource;
1010
import org.springframework.jdbc.core.JdbcTemplate;
1111
import org.springframework.jdbc.datasource.SingleConnectionDataSource;
12-
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
13-
import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
14-
import org.springframework.security.acls.domain.BasePermission;
15-
import org.springframework.security.acls.domain.ConsoleAuditLogger;
16-
import org.springframework.security.acls.domain.DefaultPermissionFactory;
17-
import org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy;
18-
import org.springframework.security.acls.domain.EhCacheBasedAclCache;
19-
import org.springframework.security.acls.domain.ObjectIdentityImpl;
20-
import org.springframework.security.acls.domain.PrincipalSid;
12+
import org.springframework.security.acls.domain.*;
2113
import org.springframework.security.acls.model.Acl;
2214
import org.springframework.security.acls.model.AuditableAccessControlEntry;
2315
import org.springframework.security.acls.model.MutableAcl;
@@ -301,4 +293,20 @@ public void nullOwnerIsNotSupported() {
301293
strategy.readAclsById(Arrays.asList(oid), Arrays.asList(BEN_SID));
302294
}
303295

296+
@Test
297+
public void testCreatePrincipalSid() {
298+
Sid result = strategy.createSid(true, "sid");
299+
300+
Assert.assertEquals(PrincipalSid.class, result.getClass());
301+
Assert.assertEquals("sid", ((PrincipalSid)result).getPrincipal());
302+
}
303+
304+
@Test
305+
public void testCreateGrantedAuthority() {
306+
Sid result = strategy.createSid(false, "sid");
307+
308+
Assert.assertEquals(GrantedAuthoritySid.class, result.getClass());
309+
Assert.assertEquals("sid", ((GrantedAuthoritySid)result).getGrantedAuthority());
310+
}
311+
304312
}

acl/src/test/java/org/springframework/security/acls/jdbc/JdbcMutableAclServiceTests.java

+40-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package org.springframework.security.acls.jdbc;
1616

1717
import static org.junit.Assert.*;
18+
import static org.mockito.Mockito.*;
1819

1920
import java.util.Arrays;
2021
import java.util.List;
@@ -43,6 +44,7 @@
4344
import org.springframework.security.acls.model.ObjectIdentity;
4445
import org.springframework.security.acls.model.Permission;
4546
import org.springframework.security.acls.model.Sid;
47+
import org.springframework.security.acls.sid.CustomSid;
4648
import org.springframework.security.authentication.TestingAuthenticationToken;
4749
import org.springframework.security.core.Authentication;
4850
import org.springframework.security.core.context.SecurityContextHolder;
@@ -489,6 +491,43 @@ public void cumulativePermissions() {
489491
assertTrue(topParent.isGranted(Arrays.asList(cm), Arrays.asList(benSid), true));
490492

491493
SecurityContextHolder.clearContext();
492-
}
494+
}
495+
@Test
496+
public void testProcessingCustomSid() {
497+
CustomJdbcMutableAclService customJdbcMutableAclService = spy(new CustomJdbcMutableAclService(dataSource,
498+
lookupStrategy, aclCache));
499+
CustomSid customSid = new CustomSid("Custom sid");
500+
when(customJdbcMutableAclService.createOrRetrieveSidPrimaryKey("Custom sid", false, false)).thenReturn(1L);
501+
502+
Long result = customJdbcMutableAclService.createOrRetrieveSidPrimaryKey(customSid, false);
503+
504+
assertEquals(result, new Long(1L));
505+
}
506+
507+
/**
508+
* This class needed to show how to extend {@link JdbcMutableAclService} for processing
509+
* custom {@link Sid} implementations
510+
*/
511+
private class CustomJdbcMutableAclService extends JdbcMutableAclService {
512+
513+
private CustomJdbcMutableAclService(DataSource dataSource, LookupStrategy lookupStrategy, AclCache aclCache) {
514+
super(dataSource, lookupStrategy, aclCache);
515+
}
516+
517+
@Override
518+
protected Long createOrRetrieveSidPrimaryKey(Sid sid, boolean allowCreate) {
519+
String sidName;
520+
boolean isPrincipal = false;
521+
if (sid instanceof CustomSid) {
522+
sidName = ((CustomSid)sid).getSid();
523+
} else if (sid instanceof GrantedAuthoritySid) {
524+
sidName = ((GrantedAuthoritySid)sid).getGrantedAuthority();
525+
} else {
526+
sidName = ((PrincipalSid)sid).getPrincipal();
527+
isPrincipal = true;
528+
}
529+
return createOrRetrieveSidPrimaryKey(sidName, isPrincipal, allowCreate);
530+
}
531+
}
493532

494533
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package org.springframework.security.acls.sid;
2+
3+
import org.springframework.security.acls.model.Sid;
4+
5+
/**
6+
* This class is example of custom {@link Sid} implementation
7+
* @author Mikhail Stryzhonok
8+
*/
9+
public class CustomSid implements Sid {
10+
11+
private String sid;
12+
13+
public CustomSid(String sid) {
14+
this.sid = sid;
15+
}
16+
17+
public String getSid() {
18+
return sid;
19+
}
20+
21+
public void setSid(String sid) {
22+
this.sid = sid;
23+
}
24+
}

0 commit comments

Comments
 (0)