Skip to content

Added possibility create custom Sid #115

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public void securityCheck(Acl acl, int changeType) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

// Check if authorized by virtue of ACL ownership
Sid currentUser = new PrincipalSid(authentication);
Sid currentUser = createCurrentUser(authentication);

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

/**
* Creates a principal-like sid from the authentication information.
*
* @param authentication the authentication information that can provide principal and thus the sid's id will be
* dependant on the value inside
* @return a sid with the ID taken from the authentication information
*/
protected Sid createCurrentUser(Authentication authentication) {
return new PrincipalSid(authentication);
}

public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
Assert.notNull(sidRetrievalStrategy, "SidRetrievalStrategy required");
this.sidRetrievalStrategy = sidRetrievalStrategy;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
*
* @author Ben Alex
*/
public final class BasicLookupStrategy implements LookupStrategy {
public class BasicLookupStrategy implements LookupStrategy {

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

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

/**
* Creates a particular implementation of {@link Sid} depending on the arguments.
*
* @param sid the name of the sid representing its unique identifier. In typical ACL database schema it's
* located in table {@code acl_sid} table, {@code sid} column.
* @param isPrincipal whether it's a user or granted authority like role
* @return the instance of Sid with the {@code sidName} as an identifier
*/
protected Sid createSid(boolean isPrincipal, String sid) {
if (isPrincipal) {
return new PrincipalSid(sid);
} else {
return new GrantedAuthoritySid(sid);
}
}

/**
* Sets the {@code PermissionFactory} instance which will be used to convert loaded permission
* data values to {@code Permission}s. A {@code DefaultPermissionFactory} will be used by default.
*
* @param permissionFactory
*/
public void setPermissionFactory(PermissionFactory permissionFactory) {
public final void setPermissionFactory(PermissionFactory permissionFactory) {
this.permissionFactory = permissionFactory;
}

public void setBatchSize(int batchSize) {
public final void setBatchSize(int batchSize) {
this.batchSize = batchSize;
}

Expand All @@ -448,28 +464,28 @@ public void setBatchSize(int batchSize) {
*
* @param selectClause the select clause, which defaults to {@link #DEFAULT_SELECT_CLAUSE}.
*/
public void setSelectClause(String selectClause) {
public final void setSelectClause(String selectClause) {
this.selectClause = selectClause;
}

/**
* The SQL for the where clause used in the <tt>lookupPrimaryKey</tt> method.
*/
public void setLookupPrimaryKeysWhereClause(String lookupPrimaryKeysWhereClause) {
public final void setLookupPrimaryKeysWhereClause(String lookupPrimaryKeysWhereClause) {
this.lookupPrimaryKeysWhereClause = lookupPrimaryKeysWhereClause;
}

/**
* The SQL for the where clause used in the <tt>lookupObjectIdentities</tt> method.
*/
public void setLookupObjectIdentitiesWhereClause(String lookupObjectIdentitiesWhereClause) {
public final void setLookupObjectIdentitiesWhereClause(String lookupObjectIdentitiesWhereClause) {
this.lookupObjectIdentitiesWhereClause = lookupObjectIdentitiesWhereClause;
}

/**
* The SQL for the "order by" clause used in both queries.
*/
public void setOrderByClause(String orderByClause) {
public final void setOrderByClause(String orderByClause) {
this.orderByClause = orderByClause;
}

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

boolean entriesInheriting = rs.getBoolean("entries_inheriting");
Sid owner;

if (rs.getBoolean("acl_principal")) {
owner = new PrincipalSid(rs.getString("acl_sid"));
} else {
owner = new GrantedAuthoritySid(rs.getString("acl_sid"));
}
Sid owner = createSid(rs.getBoolean("acl_principal"), rs.getString("acl_sid"));

acl = new AclImpl(objectIdentity, id, aclAuthorizationStrategy, grantingStrategy, parentAcl, null,
entriesInheriting, owner);
Expand All @@ -574,13 +584,7 @@ private void convertCurrentResultIntoObject(Map<Serializable, Acl> acls, ResultS
// It is permissible to have no ACEs in an ACL (which is detected by a null ACE_SID)
if (rs.getString("ace_sid") != null) {
Long aceId = new Long(rs.getLong("ace_id"));
Sid recipient;

if (rs.getBoolean("ace_principal")) {
recipient = new PrincipalSid(rs.getString("ace_sid"));
} else {
recipient = new GrantedAuthoritySid(rs.getString("ace_sid"));
}
Sid recipient = createSid(rs.getBoolean("ace_principal"), rs.getString("ace_sid"));

int mask = rs.getInt("mask");
Permission permission = permissionFactory.buildFromMask(mask);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,19 @@ protected Long createOrRetrieveSidPrimaryKey(Sid sid, boolean allowCreate) {
throw new IllegalArgumentException("Unsupported implementation of Sid");
}

return createOrRetrieveSidPrimaryKey(sidName, sidIsPrincipal, allowCreate);
}

/**
* Retrieves the primary key from acl_sid, creating a new row if needed and the allowCreate property is
* true.
* @param sidName name of Sid to find or to create
* @param sidIsPrincipal whether it's a user or granted authority like role
* @param allowCreate true if creation is permitted if not found
* @return the primary key or null if not found
*/
protected Long createOrRetrieveSidPrimaryKey(String sidName, boolean sidIsPrincipal, boolean allowCreate) {

List<Long> sidIds = jdbcTemplate.queryForList(selectSidPrimaryKey,
new Object[] {Boolean.valueOf(sidIsPrincipal), sidName}, Long.class);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,7 @@
import org.springframework.core.io.Resource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.SingleConnectionDataSource;
import org.springframework.security.acls.domain.AclAuthorizationStrategy;
import org.springframework.security.acls.domain.AclAuthorizationStrategyImpl;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.acls.domain.ConsoleAuditLogger;
import org.springframework.security.acls.domain.DefaultPermissionFactory;
import org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy;
import org.springframework.security.acls.domain.EhCacheBasedAclCache;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.domain.PrincipalSid;
import org.springframework.security.acls.domain.*;
import org.springframework.security.acls.model.Acl;
import org.springframework.security.acls.model.AuditableAccessControlEntry;
import org.springframework.security.acls.model.MutableAcl;
Expand Down Expand Up @@ -301,4 +293,20 @@ public void nullOwnerIsNotSupported() {
strategy.readAclsById(Arrays.asList(oid), Arrays.asList(BEN_SID));
}

@Test
public void testCreatePrincipalSid() {
Sid result = strategy.createSid(true, "sid");

Assert.assertEquals(PrincipalSid.class, result.getClass());
Assert.assertEquals("sid", ((PrincipalSid)result).getPrincipal());
}

@Test
public void testCreateGrantedAuthority() {
Sid result = strategy.createSid(false, "sid");

Assert.assertEquals(GrantedAuthoritySid.class, result.getClass());
Assert.assertEquals("sid", ((GrantedAuthoritySid)result).getGrantedAuthority());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package org.springframework.security.acls.jdbc;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

import java.util.Arrays;
import java.util.List;
Expand Down Expand Up @@ -43,6 +44,7 @@
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.Permission;
import org.springframework.security.acls.model.Sid;
import org.springframework.security.acls.sid.CustomSid;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
Expand Down Expand Up @@ -488,6 +490,43 @@ public void cumulativePermissions() {
assertTrue(topParent.isGranted(Arrays.asList(cm), Arrays.asList(benSid), true));

SecurityContextHolder.clearContext();
}
}
@Test
public void testProcessingCustomSid() {
CustomJdbcMutableAclService customJdbcMutableAclService = spy(new CustomJdbcMutableAclService(dataSource,
lookupStrategy, aclCache));
CustomSid customSid = new CustomSid("Custom sid");
when(customJdbcMutableAclService.createOrRetrieveSidPrimaryKey("Custom sid", false, false)).thenReturn(1L);

Long result = customJdbcMutableAclService.createOrRetrieveSidPrimaryKey(customSid, false);

assertEquals(result, new Long(1L));
}

/**
* This class needed to show how to extend {@link JdbcMutableAclService} for processing
* custom {@link Sid} implementations
*/
private class CustomJdbcMutableAclService extends JdbcMutableAclService {

private CustomJdbcMutableAclService(DataSource dataSource, LookupStrategy lookupStrategy, AclCache aclCache) {
super(dataSource, lookupStrategy, aclCache);
}

@Override
protected Long createOrRetrieveSidPrimaryKey(Sid sid, boolean allowCreate) {
String sidName;
boolean isPrincipal = false;
if (sid instanceof CustomSid) {
sidName = ((CustomSid)sid).getSid();
} else if (sid instanceof GrantedAuthoritySid) {
sidName = ((GrantedAuthoritySid)sid).getGrantedAuthority();
} else {
sidName = ((PrincipalSid)sid).getPrincipal();
isPrincipal = true;
}
return createOrRetrieveSidPrimaryKey(sidName, isPrincipal, allowCreate);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.springframework.security.acls.sid;

import org.springframework.security.acls.model.Sid;

/**
* This class is example of custom {@link Sid} implementation
* @author Mikhail Stryzhonok
*/
public class CustomSid implements Sid {

private String sid;

public CustomSid(String sid) {
this.sid = sid;
}

public String getSid() {
return sid;
}

public void setSid(String sid) {
this.sid = sid;
}
}