mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-05-31 01:02:14 +00:00
Allow use of non-numeric (e.g. UUID) values for ObjectIdentity.getIdentifier()
Prior to this commit, the ObjectIdentity id had to be a number. This commit allows for domain objects to use UUIDs as their identifier. The fully qualified class name of the identifier type can be specified in the acl_object_identity table and a ConversionService can be provided to BasicLookupStrategy to convert from String to the actual identifier type. There are the following other changes: - BasicLookupStrategy has a new property, aclClassIdSupported, which is used to retrieve the new column from the database. This preserves backwards-compatibility, as it is false by default. - JdbcMutableAclService has the same property, aclClassIdSupported, which is needed to modify the insert statement to write to the new column. Defaults to false for backwards-compatibility. - Tests have been updated to verify both the existing functionality for backwards-compatibility and the new functionality. Fixes gh-1224
This commit is contained in:
parent
de9fe3e3b1
commit
6decf1c8ef
@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2017 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.security.acls.jdbc;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.core.convert.ConversionService;
|
||||||
|
import org.springframework.security.acls.model.ObjectIdentity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class for helping convert database representations of {@link ObjectIdentity#getIdentifier()} into
|
||||||
|
* the correct Java type as specified by <code>acl_class.class_id_type</code>.
|
||||||
|
* @author paulwheeler
|
||||||
|
*/
|
||||||
|
class AclClassIdUtils {
|
||||||
|
private static final String DEFAULT_CLASS_ID_TYPE_COLUMN_NAME = "class_id_type";
|
||||||
|
private static final Log log = LogFactory.getLog(AclClassIdUtils.class);
|
||||||
|
|
||||||
|
private ConversionService conversionService;
|
||||||
|
|
||||||
|
public AclClassIdUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the raw type from the database into the right Java type. For most applications the 'raw type' will be Long, for some applications
|
||||||
|
* it could be String.
|
||||||
|
* @param identifier The identifier from the database
|
||||||
|
* @param resultSet Result set of the query
|
||||||
|
* @return The identifier in the appropriate target Java type. Typically Long or UUID.
|
||||||
|
* @throws SQLException
|
||||||
|
*/
|
||||||
|
Serializable identifierFrom(Serializable identifier, ResultSet resultSet) throws SQLException {
|
||||||
|
if (isString(identifier) && hasValidClassIdType(resultSet)
|
||||||
|
&& canConvertFromStringTo(classIdTypeFrom(resultSet))) {
|
||||||
|
|
||||||
|
identifier = convertFromStringTo((String) identifier, classIdTypeFrom(resultSet));
|
||||||
|
} else {
|
||||||
|
// Assume it should be a Long type
|
||||||
|
identifier = convertToLong(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
return identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasValidClassIdType(ResultSet resultSet) throws SQLException {
|
||||||
|
boolean hasClassIdType = false;
|
||||||
|
try {
|
||||||
|
hasClassIdType = classIdTypeFrom(resultSet) != null;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.debug("Unable to obtain the class id type", e);
|
||||||
|
}
|
||||||
|
return hasClassIdType;
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends Serializable> Class<T> classIdTypeFrom(ResultSet resultSet) throws SQLException {
|
||||||
|
return classIdTypeFrom(resultSet.getString(DEFAULT_CLASS_ID_TYPE_COLUMN_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends Serializable> Class<T> classIdTypeFrom(String className) {
|
||||||
|
Class targetType = null;
|
||||||
|
if (className != null) {
|
||||||
|
try {
|
||||||
|
targetType = Class.forName(className);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
log.debug("Unable to find class id type on classpath", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return targetType;
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> boolean canConvertFromStringTo(Class<T> targetType) {
|
||||||
|
return hasConversionService() && conversionService.canConvert(String.class, targetType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T extends Serializable> T convertFromStringTo(String identifier, Class<T> targetType) {
|
||||||
|
return conversionService.convert(identifier, targetType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasConversionService() {
|
||||||
|
return conversionService != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts to a {@link Long}, attempting to use the {@link ConversionService} if available.
|
||||||
|
* @param identifier The identifier
|
||||||
|
* @return Long version of the identifier
|
||||||
|
* @throws NumberFormatException if the string cannot be parsed to a long.
|
||||||
|
* @throws org.springframework.core.convert.ConversionException if a conversion exception occurred
|
||||||
|
* @throws IllegalArgumentException if targetType is null
|
||||||
|
*/
|
||||||
|
private Long convertToLong(Serializable identifier) {
|
||||||
|
Long idAsLong;
|
||||||
|
if (hasConversionService()) {
|
||||||
|
idAsLong = conversionService.convert(identifier, Long.class);
|
||||||
|
} else {
|
||||||
|
idAsLong = Long.valueOf(identifier.toString());
|
||||||
|
}
|
||||||
|
return idAsLong;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isString(Serializable object) {
|
||||||
|
return object.getClass().isAssignableFrom(String.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConversionService(ConversionService conversionService) {
|
||||||
|
this.conversionService = conversionService;
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
* Copyright 2004, 2005, 2006, 2017 Acegi Technology Pty Limited
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -30,6 +30,9 @@ import java.util.Set;
|
|||||||
|
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.springframework.core.convert.ConversionException;
|
||||||
|
import org.springframework.core.convert.ConversionService;
|
||||||
|
import org.springframework.core.convert.support.DefaultConversionService;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.jdbc.core.PreparedStatementSetter;
|
import org.springframework.jdbc.core.PreparedStatementSetter;
|
||||||
import org.springframework.jdbc.core.ResultSetExtractor;
|
import org.springframework.jdbc.core.ResultSetExtractor;
|
||||||
@ -78,7 +81,7 @@ import org.springframework.util.Assert;
|
|||||||
*/
|
*/
|
||||||
public class BasicLookupStrategy implements LookupStrategy {
|
public class BasicLookupStrategy implements LookupStrategy {
|
||||||
|
|
||||||
public final static String DEFAULT_SELECT_CLAUSE = "select acl_object_identity.object_id_identity, "
|
private final static String DEFAULT_SELECT_CLAUSE_COLUMNS = "select acl_object_identity.object_id_identity, "
|
||||||
+ "acl_entry.ace_order, "
|
+ "acl_entry.ace_order, "
|
||||||
+ "acl_object_identity.id as acl_id, "
|
+ "acl_object_identity.id as acl_id, "
|
||||||
+ "acl_object_identity.parent_object, "
|
+ "acl_object_identity.parent_object, "
|
||||||
@ -92,13 +95,19 @@ public class BasicLookupStrategy implements LookupStrategy {
|
|||||||
+ "acl_sid.sid as ace_sid, "
|
+ "acl_sid.sid as ace_sid, "
|
||||||
+ "acli_sid.principal as acl_principal, "
|
+ "acli_sid.principal as acl_principal, "
|
||||||
+ "acli_sid.sid as acl_sid, "
|
+ "acli_sid.sid as acl_sid, "
|
||||||
+ "acl_class.class "
|
+ "acl_class.class ";
|
||||||
+ "from acl_object_identity "
|
private final static String DEFAULT_SELECT_CLAUSE_ACL_CLASS_ID_TYPE_COLUMN = ", acl_class.class_id_type ";
|
||||||
|
private final static String DEFAULT_SELECT_CLAUSE_FROM = "from acl_object_identity "
|
||||||
+ "left join acl_sid acli_sid on acli_sid.id = acl_object_identity.owner_sid "
|
+ "left join acl_sid acli_sid on acli_sid.id = acl_object_identity.owner_sid "
|
||||||
+ "left join acl_class on acl_class.id = acl_object_identity.object_id_class "
|
+ "left join acl_class on acl_class.id = acl_object_identity.object_id_class "
|
||||||
+ "left join acl_entry on acl_object_identity.id = acl_entry.acl_object_identity "
|
+ "left join acl_entry on acl_object_identity.id = acl_entry.acl_object_identity "
|
||||||
+ "left join acl_sid on acl_entry.sid = acl_sid.id " + "where ( ";
|
+ "left join acl_sid on acl_entry.sid = acl_sid.id " + "where ( ";
|
||||||
|
|
||||||
|
public final static String DEFAULT_SELECT_CLAUSE = DEFAULT_SELECT_CLAUSE_COLUMNS + DEFAULT_SELECT_CLAUSE_FROM;
|
||||||
|
|
||||||
|
public final static String DEFAULT_ACL_CLASS_ID_SELECT_CLAUSE = DEFAULT_SELECT_CLAUSE_COLUMNS +
|
||||||
|
DEFAULT_SELECT_CLAUSE_ACL_CLASS_ID_TYPE_COLUMN + DEFAULT_SELECT_CLAUSE_FROM;
|
||||||
|
|
||||||
private final static String DEFAULT_LOOKUP_KEYS_WHERE_CLAUSE = "(acl_object_identity.id = ?)";
|
private final static String DEFAULT_LOOKUP_KEYS_WHERE_CLAUSE = "(acl_object_identity.id = ?)";
|
||||||
|
|
||||||
private final static String DEFAULT_LOOKUP_IDENTITIES_WHERE_CLAUSE = "(acl_object_identity.object_id_identity = ? and acl_class.class = ?)";
|
private final static String DEFAULT_LOOKUP_IDENTITIES_WHERE_CLAUSE = "(acl_object_identity.object_id_identity = ? and acl_class.class = ?)";
|
||||||
@ -126,6 +135,8 @@ public class BasicLookupStrategy implements LookupStrategy {
|
|||||||
private String lookupObjectIdentitiesWhereClause = DEFAULT_LOOKUP_IDENTITIES_WHERE_CLAUSE;
|
private String lookupObjectIdentitiesWhereClause = DEFAULT_LOOKUP_IDENTITIES_WHERE_CLAUSE;
|
||||||
private String orderByClause = DEFAULT_ORDER_BY_CLAUSE;
|
private String orderByClause = DEFAULT_ORDER_BY_CLAUSE;
|
||||||
|
|
||||||
|
private AclClassIdUtils aclClassIdUtils;
|
||||||
|
|
||||||
// ~ Constructors
|
// ~ Constructors
|
||||||
// ===================================================================================================
|
// ===================================================================================================
|
||||||
|
|
||||||
@ -161,9 +172,9 @@ public class BasicLookupStrategy implements LookupStrategy {
|
|||||||
this.aclCache = aclCache;
|
this.aclCache = aclCache;
|
||||||
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
|
this.aclAuthorizationStrategy = aclAuthorizationStrategy;
|
||||||
this.grantingStrategy = grantingStrategy;
|
this.grantingStrategy = grantingStrategy;
|
||||||
|
this.aclClassIdUtils = new AclClassIdUtils();
|
||||||
fieldAces.setAccessible(true);
|
fieldAces.setAccessible(true);
|
||||||
fieldAcl.setAccessible(true);
|
fieldAcl.setAccessible(true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ~ Methods
|
// ~ Methods
|
||||||
@ -383,10 +394,9 @@ public class BasicLookupStrategy implements LookupStrategy {
|
|||||||
// No need to check for nulls, as guaranteed non-null by
|
// No need to check for nulls, as guaranteed non-null by
|
||||||
// ObjectIdentity.getIdentifier() interface contract
|
// ObjectIdentity.getIdentifier() interface contract
|
||||||
String identifier = oid.getIdentifier().toString();
|
String identifier = oid.getIdentifier().toString();
|
||||||
long id = (Long.valueOf(identifier)).longValue();
|
|
||||||
|
|
||||||
// Inject values
|
// Inject values
|
||||||
ps.setLong((2 * i) + 1, id);
|
ps.setString((2 * i) + 1, identifier);
|
||||||
ps.setString((2 * i) + 2, type);
|
ps.setString((2 * i) + 2, type);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
@ -537,6 +547,18 @@ public class BasicLookupStrategy implements LookupStrategy {
|
|||||||
this.orderByClause = orderByClause;
|
this.orderByClause = orderByClause;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final void setAclClassIdSupported(boolean aclClassIdSupported) {
|
||||||
|
if (aclClassIdSupported) {
|
||||||
|
Assert.isTrue(this.selectClause.equals(DEFAULT_SELECT_CLAUSE), "Cannot set aclClassIdSupported and override the select clause; "
|
||||||
|
+ "just override the select clause");
|
||||||
|
this.selectClause = DEFAULT_ACL_CLASS_ID_SELECT_CLAUSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setAclClassIdUtils(AclClassIdUtils aclClassIdUtils) {
|
||||||
|
this.aclClassIdUtils = aclClassIdUtils;
|
||||||
|
}
|
||||||
|
|
||||||
// ~ Inner Classes
|
// ~ Inner Classes
|
||||||
// ==================================================================================================
|
// ==================================================================================================
|
||||||
|
|
||||||
@ -602,6 +624,7 @@ public class BasicLookupStrategy implements LookupStrategy {
|
|||||||
* @param rs the ResultSet focused on a current row
|
* @param rs the ResultSet focused on a current row
|
||||||
*
|
*
|
||||||
* @throws SQLException if something goes wrong converting values
|
* @throws SQLException if something goes wrong converting values
|
||||||
|
* @throws ConversionException if can't convert to the desired Java type
|
||||||
*/
|
*/
|
||||||
private void convertCurrentResultIntoObject(Map<Serializable, Acl> acls,
|
private void convertCurrentResultIntoObject(Map<Serializable, Acl> acls,
|
||||||
ResultSet rs) throws SQLException {
|
ResultSet rs) throws SQLException {
|
||||||
@ -612,9 +635,12 @@ public class BasicLookupStrategy implements LookupStrategy {
|
|||||||
|
|
||||||
if (acl == null) {
|
if (acl == null) {
|
||||||
// Make an AclImpl and pop it into the Map
|
// Make an AclImpl and pop it into the Map
|
||||||
|
|
||||||
|
// If the Java type is a String, check to see if we can convert it to the target id type, e.g. UUID.
|
||||||
|
Serializable identifier = (Serializable) rs.getObject("object_id_identity");
|
||||||
|
identifier = aclClassIdUtils.identifierFrom(identifier, rs);
|
||||||
ObjectIdentity objectIdentity = new ObjectIdentityImpl(
|
ObjectIdentity objectIdentity = new ObjectIdentityImpl(
|
||||||
rs.getString("class"), Long.valueOf(rs
|
rs.getString("class"), identifier);
|
||||||
.getLong("object_id_identity")));
|
|
||||||
|
|
||||||
Acl parentAcl = null;
|
Acl parentAcl = null;
|
||||||
long parentAclId = rs.getLong("parent_object");
|
long parentAclId = rs.getLong("parent_object");
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
* Copyright 2004, 2005, 2006, 2017 Acegi Technology Pty Limited
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.security.acls.jdbc;
|
package org.springframework.security.acls.jdbc;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -49,8 +50,15 @@ public class JdbcAclService implements AclService {
|
|||||||
// =====================================================================================
|
// =====================================================================================
|
||||||
|
|
||||||
protected static final Log log = LogFactory.getLog(JdbcAclService.class);
|
protected static final Log log = LogFactory.getLog(JdbcAclService.class);
|
||||||
private static final String DEFAULT_SELECT_ACL_WITH_PARENT_SQL = "select obj.object_id_identity as obj_id, class.class as class "
|
private static final String DEFAULT_SELECT_ACL_CLASS_COLUMNS = "class.class as class";
|
||||||
+ "from acl_object_identity obj, acl_object_identity parent, acl_class class "
|
private static final String DEFAULT_SELECT_ACL_CLASS_COLUMNS_WITH_ID_TYPE = DEFAULT_SELECT_ACL_CLASS_COLUMNS + ", class.class_id_type as class_id_type";
|
||||||
|
private static final String DEFAULT_SELECT_ACL_WITH_PARENT_SQL = "select obj.object_id_identity as obj_id, " + DEFAULT_SELECT_ACL_CLASS_COLUMNS
|
||||||
|
+ " from acl_object_identity obj, acl_object_identity parent, acl_class class "
|
||||||
|
+ "where obj.parent_object = parent.id and obj.object_id_class = class.id "
|
||||||
|
+ "and parent.object_id_identity = ? and parent.object_id_class = ("
|
||||||
|
+ "select id FROM acl_class where acl_class.class = ?)";
|
||||||
|
private static final String DEFAULT_SELECT_ACL_WITH_PARENT_SQL_WITH_CLASS_ID_TYPE = "select obj.object_id_identity as obj_id, " + DEFAULT_SELECT_ACL_CLASS_COLUMNS_WITH_ID_TYPE
|
||||||
|
+ " from acl_object_identity obj, acl_object_identity parent, acl_class class "
|
||||||
+ "where obj.parent_object = parent.id and obj.object_id_class = class.id "
|
+ "where obj.parent_object = parent.id and obj.object_id_class = class.id "
|
||||||
+ "and parent.object_id_identity = ? and parent.object_id_class = ("
|
+ "and parent.object_id_identity = ? and parent.object_id_class = ("
|
||||||
+ "select id FROM acl_class where acl_class.class = ?)";
|
+ "select id FROM acl_class where acl_class.class = ?)";
|
||||||
@ -60,7 +68,9 @@ public class JdbcAclService implements AclService {
|
|||||||
|
|
||||||
protected final JdbcTemplate jdbcTemplate;
|
protected final JdbcTemplate jdbcTemplate;
|
||||||
private final LookupStrategy lookupStrategy;
|
private final LookupStrategy lookupStrategy;
|
||||||
|
private boolean aclClassIdSupported;
|
||||||
private String findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL;
|
private String findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL;
|
||||||
|
private AclClassIdUtils aclClassIdUtils;
|
||||||
|
|
||||||
// ~ Constructors
|
// ~ Constructors
|
||||||
// ===================================================================================================
|
// ===================================================================================================
|
||||||
@ -70,6 +80,7 @@ public class JdbcAclService implements AclService {
|
|||||||
Assert.notNull(lookupStrategy, "LookupStrategy required");
|
Assert.notNull(lookupStrategy, "LookupStrategy required");
|
||||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||||
this.lookupStrategy = lookupStrategy;
|
this.lookupStrategy = lookupStrategy;
|
||||||
|
this.aclClassIdUtils = new AclClassIdUtils();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ~ Methods
|
// ~ Methods
|
||||||
@ -82,7 +93,8 @@ public class JdbcAclService implements AclService {
|
|||||||
public ObjectIdentity mapRow(ResultSet rs, int rowNum)
|
public ObjectIdentity mapRow(ResultSet rs, int rowNum)
|
||||||
throws SQLException {
|
throws SQLException {
|
||||||
String javaType = rs.getString("class");
|
String javaType = rs.getString("class");
|
||||||
Long identifier = new Long(rs.getLong("obj_id"));
|
Serializable identifier = (Serializable) rs.getObject("obj_id");
|
||||||
|
identifier = aclClassIdUtils.identifierFrom(identifier, rs);
|
||||||
|
|
||||||
return new ObjectIdentityImpl(javaType, identifier);
|
return new ObjectIdentityImpl(javaType, identifier);
|
||||||
}
|
}
|
||||||
@ -138,4 +150,24 @@ public class JdbcAclService implements AclService {
|
|||||||
public void setFindChildrenQuery(String findChildrenSql) {
|
public void setFindChildrenQuery(String findChildrenSql) {
|
||||||
this.findChildrenSql = findChildrenSql;
|
this.findChildrenSql = findChildrenSql;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAclClassIdSupported(boolean aclClassIdSupported) {
|
||||||
|
this.aclClassIdSupported = aclClassIdSupported;
|
||||||
|
if (aclClassIdSupported) {
|
||||||
|
// Change the default insert if it hasn't been overridden
|
||||||
|
if (this.findChildrenSql.equals(DEFAULT_SELECT_ACL_WITH_PARENT_SQL)) {
|
||||||
|
this.findChildrenSql = DEFAULT_SELECT_ACL_WITH_PARENT_SQL_WITH_CLASS_ID_TYPE;
|
||||||
|
} else {
|
||||||
|
log.debug("Find children statement has already been overridden, so not overridding the default");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAclClassIdUtils(AclClassIdUtils aclClassIdUtils) {
|
||||||
|
this.aclClassIdUtils = aclClassIdUtils;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isAclClassIdSupported() {
|
||||||
|
return aclClassIdSupported;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
* Copyright 2004, 2005, 2006, 2017 Acegi Technology Pty Limited
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -58,6 +58,8 @@ import org.springframework.util.Assert;
|
|||||||
* @author Johannes Zlattinger
|
* @author Johannes Zlattinger
|
||||||
*/
|
*/
|
||||||
public class JdbcMutableAclService extends JdbcAclService implements MutableAclService {
|
public class JdbcMutableAclService extends JdbcAclService implements MutableAclService {
|
||||||
|
private static final String DEFAULT_INSERT_INTO_ACL_CLASS = "insert into acl_class (class) values (?)";
|
||||||
|
private static final String DEFAULT_INSERT_INTO_ACL_CLASS_WITH_ID = "insert into acl_class (class, class_id_type) values (?, ?)";
|
||||||
// ~ Instance fields
|
// ~ Instance fields
|
||||||
// ================================================================================================
|
// ================================================================================================
|
||||||
|
|
||||||
@ -67,7 +69,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
|||||||
private String deleteObjectIdentityByPrimaryKey = "delete from acl_object_identity where id=?";
|
private String deleteObjectIdentityByPrimaryKey = "delete from acl_object_identity where id=?";
|
||||||
private String classIdentityQuery = "call identity()";
|
private String classIdentityQuery = "call identity()";
|
||||||
private String sidIdentityQuery = "call identity()";
|
private String sidIdentityQuery = "call identity()";
|
||||||
private String insertClass = "insert into acl_class (class) values (?)";
|
private String insertClass = DEFAULT_INSERT_INTO_ACL_CLASS;
|
||||||
private String insertEntry = "insert into acl_entry "
|
private String insertEntry = "insert into acl_entry "
|
||||||
+ "(acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure)"
|
+ "(acl_object_identity, ace_order, sid, mask, granting, audit_success, audit_failure)"
|
||||||
+ "values (?, ?, ?, ?, ?, ?, ?)";
|
+ "values (?, ?, ?, ?, ?, ?, ?)";
|
||||||
@ -167,7 +169,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
|||||||
*/
|
*/
|
||||||
protected void createObjectIdentity(ObjectIdentity object, Sid owner) {
|
protected void createObjectIdentity(ObjectIdentity object, Sid owner) {
|
||||||
Long sidId = createOrRetrieveSidPrimaryKey(owner, true);
|
Long sidId = createOrRetrieveSidPrimaryKey(owner, true);
|
||||||
Long classId = createOrRetrieveClassPrimaryKey(object.getType(), true);
|
Long classId = createOrRetrieveClassPrimaryKey(object.getType(), true, object.getIdentifier().getClass());
|
||||||
jdbcTemplate.update(insertObjectIdentity, classId, object.getIdentifier(), sidId,
|
jdbcTemplate.update(insertObjectIdentity, classId, object.getIdentifier(), sidId,
|
||||||
Boolean.TRUE);
|
Boolean.TRUE);
|
||||||
}
|
}
|
||||||
@ -181,7 +183,7 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
|||||||
*
|
*
|
||||||
* @return the primary key or null if not found
|
* @return the primary key or null if not found
|
||||||
*/
|
*/
|
||||||
protected Long createOrRetrieveClassPrimaryKey(String type, boolean allowCreate) {
|
protected Long createOrRetrieveClassPrimaryKey(String type, boolean allowCreate, Class idType) {
|
||||||
List<Long> classIds = jdbcTemplate.queryForList(selectClassPrimaryKey,
|
List<Long> classIds = jdbcTemplate.queryForList(selectClassPrimaryKey,
|
||||||
new Object[] { type }, Long.class);
|
new Object[] { type }, Long.class);
|
||||||
|
|
||||||
@ -190,7 +192,11 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (allowCreate) {
|
if (allowCreate) {
|
||||||
jdbcTemplate.update(insertClass, type);
|
if (!isAclClassIdSupported()) {
|
||||||
|
jdbcTemplate.update(insertClass, type);
|
||||||
|
} else {
|
||||||
|
jdbcTemplate.update(insertClass, type, idType.getCanonicalName());
|
||||||
|
}
|
||||||
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(),
|
Assert.isTrue(TransactionSynchronizationManager.isSynchronizationActive(),
|
||||||
"Transaction must be running");
|
"Transaction must be running");
|
||||||
return jdbcTemplate.queryForObject(classIdentityQuery, Long.class);
|
return jdbcTemplate.queryForObject(classIdentityQuery, Long.class);
|
||||||
@ -485,4 +491,17 @@ public class JdbcMutableAclService extends JdbcAclService implements MutableAclS
|
|||||||
public void setForeignKeysInDatabase(boolean foreignKeysInDatabase) {
|
public void setForeignKeysInDatabase(boolean foreignKeysInDatabase) {
|
||||||
this.foreignKeysInDatabase = foreignKeysInDatabase;
|
this.foreignKeysInDatabase = foreignKeysInDatabase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAclClassIdSupported(boolean aclClassIdSupported) {
|
||||||
|
super.setAclClassIdSupported(aclClassIdSupported);
|
||||||
|
if (aclClassIdSupported) {
|
||||||
|
// Change the default insert if it hasn't been overridden
|
||||||
|
if (this.insertClass.equals(DEFAULT_INSERT_INTO_ACL_CLASS)) {
|
||||||
|
this.insertClass = DEFAULT_INSERT_INTO_ACL_CLASS_WITH_ID;
|
||||||
|
} else {
|
||||||
|
log.debug("Insert class statement has already been overridden, so not overridding the default");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ CREATE TABLE acl_class (
|
|||||||
CREATE TABLE acl_object_identity (
|
CREATE TABLE acl_object_identity (
|
||||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
object_id_class BIGINT UNSIGNED NOT NULL,
|
object_id_class BIGINT UNSIGNED NOT NULL,
|
||||||
object_id_identity BIGINT NOT NULL,
|
object_id_identity VARCHAR(36) NOT NULL,
|
||||||
parent_object BIGINT UNSIGNED,
|
parent_object BIGINT UNSIGNED,
|
||||||
owner_sid BIGINT UNSIGNED,
|
owner_sid BIGINT UNSIGNED,
|
||||||
entries_inheriting BOOLEAN NOT NULL,
|
entries_inheriting BOOLEAN NOT NULL,
|
||||||
|
@ -43,7 +43,7 @@ END;
|
|||||||
CREATE TABLE acl_object_identity (
|
CREATE TABLE acl_object_identity (
|
||||||
id NUMBER(38) NOT NULL PRIMARY KEY,
|
id NUMBER(38) NOT NULL PRIMARY KEY,
|
||||||
object_id_class NUMBER(38) NOT NULL,
|
object_id_class NUMBER(38) NOT NULL,
|
||||||
object_id_identity NUMBER(38) NOT NULL,
|
object_id_identity NVARCHAR2(36) NOT NULL,
|
||||||
parent_object NUMBER(38),
|
parent_object NUMBER(38),
|
||||||
owner_sid NUMBER(38),
|
owner_sid NUMBER(38),
|
||||||
entries_inheriting NUMBER(1) NOT NULL CHECK (entries_inheriting in (0, 1)),
|
entries_inheriting NUMBER(1) NOT NULL CHECK (entries_inheriting in (0, 1)),
|
||||||
|
@ -15,13 +15,14 @@ create table acl_sid(
|
|||||||
create table acl_class(
|
create table acl_class(
|
||||||
id bigserial not null primary key,
|
id bigserial not null primary key,
|
||||||
class varchar(100) not null,
|
class varchar(100) not null,
|
||||||
|
class_id_type varchar(100),
|
||||||
constraint unique_uk_2 unique(class)
|
constraint unique_uk_2 unique(class)
|
||||||
);
|
);
|
||||||
|
|
||||||
create table acl_object_identity(
|
create table acl_object_identity(
|
||||||
id bigserial primary key,
|
id bigserial primary key,
|
||||||
object_id_class bigint not null,
|
object_id_class bigint not null,
|
||||||
object_id_identity bigint not null,
|
object_id_identity varchar(36) not null,
|
||||||
parent_object bigint,
|
parent_object bigint,
|
||||||
owner_sid bigint,
|
owner_sid bigint,
|
||||||
entries_inheriting boolean not null,
|
entries_inheriting boolean not null,
|
||||||
|
@ -21,7 +21,7 @@ CREATE TABLE acl_class (
|
|||||||
CREATE TABLE acl_object_identity (
|
CREATE TABLE acl_object_identity (
|
||||||
id BIGINT NOT NULL IDENTITY PRIMARY KEY,
|
id BIGINT NOT NULL IDENTITY PRIMARY KEY,
|
||||||
object_id_class BIGINT NOT NULL,
|
object_id_class BIGINT NOT NULL,
|
||||||
object_id_identity BIGINT NOT NULL,
|
object_id_identity VARCHAR(36) NOT NULL,
|
||||||
parent_object BIGINT,
|
parent_object BIGINT,
|
||||||
owner_sid BIGINT,
|
owner_sid BIGINT,
|
||||||
entries_inheriting BIT NOT NULL,
|
entries_inheriting BIT NOT NULL,
|
||||||
|
47
acl/src/main/resources/createAclSchemaWithAclClassIdType.sql
Normal file
47
acl/src/main/resources/createAclSchemaWithAclClassIdType.sql
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
-- ACL schema sql used in HSQLDB
|
||||||
|
|
||||||
|
-- drop table acl_entry;
|
||||||
|
-- drop table acl_object_identity;
|
||||||
|
-- drop table acl_class;
|
||||||
|
-- drop table acl_sid;
|
||||||
|
|
||||||
|
create table acl_sid(
|
||||||
|
id bigint generated by default as identity(start with 100) not null 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 generated by default as identity(start with 100) not null primary key,
|
||||||
|
class varchar_ignorecase(100) not null,
|
||||||
|
class_id_type varchar_ignorecase(100),
|
||||||
|
constraint unique_uk_2 unique(class)
|
||||||
|
);
|
||||||
|
|
||||||
|
create table acl_object_identity(
|
||||||
|
id bigint generated by default as identity(start with 100) not null primary key,
|
||||||
|
object_id_class bigint not null,
|
||||||
|
object_id_identity varchar_ignorecase(36) 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 generated by default as identity(start with 100) not null 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)
|
||||||
|
);
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2017 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.security.acls;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dummy domain object class with a {@link UUID} for the Id.
|
||||||
|
*
|
||||||
|
* @author Luke Taylor
|
||||||
|
*/
|
||||||
|
public final class TargetObjectWithUUID {
|
||||||
|
|
||||||
|
private UUID id;
|
||||||
|
|
||||||
|
public UUID getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(UUID id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,341 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2017 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.security.acls.jdbc;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.*;
|
||||||
|
|
||||||
|
import net.sf.ehcache.Cache;
|
||||||
|
import net.sf.ehcache.CacheManager;
|
||||||
|
import net.sf.ehcache.Ehcache;
|
||||||
|
|
||||||
|
import org.junit.*;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
import org.springframework.security.acls.TargetObject;
|
||||||
|
import org.springframework.security.acls.TargetObjectWithUUID;
|
||||||
|
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;
|
||||||
|
import org.springframework.security.acls.model.NotFoundException;
|
||||||
|
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.core.authority.SimpleGrantedAuthority;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests {@link BasicLookupStrategy}
|
||||||
|
*
|
||||||
|
* @author Andrei Stefan
|
||||||
|
*/
|
||||||
|
public abstract class AbstractBasicLookupStrategyTests {
|
||||||
|
|
||||||
|
protected static final Sid BEN_SID = new PrincipalSid("ben");
|
||||||
|
protected static final String TARGET_CLASS = TargetObject.class.getName();
|
||||||
|
protected static final String TARGET_CLASS_WITH_UUID = TargetObjectWithUUID.class.getName();
|
||||||
|
protected static final UUID OBJECT_IDENTITY_UUID = UUID.randomUUID();
|
||||||
|
protected static final Long OBJECT_IDENTITY_LONG_AS_UUID = 110L;
|
||||||
|
|
||||||
|
// ~ Instance fields
|
||||||
|
// ================================================================================================
|
||||||
|
|
||||||
|
private BasicLookupStrategy strategy;
|
||||||
|
private static CacheManager cacheManager;
|
||||||
|
|
||||||
|
// ~ Methods
|
||||||
|
// ========================================================================================================
|
||||||
|
|
||||||
|
public abstract JdbcTemplate getJdbcTemplate();
|
||||||
|
|
||||||
|
public abstract DataSource getDataSource();
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void initCacheManaer() {
|
||||||
|
cacheManager = CacheManager.create();
|
||||||
|
cacheManager.addCache(new Cache("basiclookuptestcache", 500, false, false, 30, 30));
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void shutdownCacheManager() {
|
||||||
|
cacheManager.removalAll();
|
||||||
|
cacheManager.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void populateDatabase() {
|
||||||
|
String query = "INSERT INTO acl_sid(ID,PRINCIPAL,SID) VALUES (1,1,'ben');"
|
||||||
|
+ "INSERT INTO acl_class(ID,CLASS) VALUES (2,'" + TARGET_CLASS + "');"
|
||||||
|
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (1,2,100,null,1,1);"
|
||||||
|
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (2,2,101,1,1,1);"
|
||||||
|
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (3,2,102,2,1,1);"
|
||||||
|
+ "INSERT INTO acl_entry(ID,ACL_OBJECT_IDENTITY,ACE_ORDER,SID,MASK,GRANTING,AUDIT_SUCCESS,AUDIT_FAILURE) VALUES (1,1,0,1,1,1,0,0);"
|
||||||
|
+ "INSERT INTO acl_entry(ID,ACL_OBJECT_IDENTITY,ACE_ORDER,SID,MASK,GRANTING,AUDIT_SUCCESS,AUDIT_FAILURE) VALUES (2,1,1,1,2,0,0,0);"
|
||||||
|
+ "INSERT INTO acl_entry(ID,ACL_OBJECT_IDENTITY,ACE_ORDER,SID,MASK,GRANTING,AUDIT_SUCCESS,AUDIT_FAILURE) VALUES (3,2,0,1,8,1,0,0);"
|
||||||
|
+ "INSERT INTO acl_entry(ID,ACL_OBJECT_IDENTITY,ACE_ORDER,SID,MASK,GRANTING,AUDIT_SUCCESS,AUDIT_FAILURE) VALUES (4,3,0,1,8,0,0,0);";
|
||||||
|
getJdbcTemplate().execute(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void initializeBeans() {
|
||||||
|
strategy = new BasicLookupStrategy(getDataSource(), aclCache(), aclAuthStrategy(),
|
||||||
|
new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()));
|
||||||
|
strategy.setPermissionFactory(new DefaultPermissionFactory());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AclAuthorizationStrategy aclAuthStrategy() {
|
||||||
|
return new AclAuthorizationStrategyImpl(
|
||||||
|
new SimpleGrantedAuthority("ROLE_ADMINISTRATOR"));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected EhCacheBasedAclCache aclCache() {
|
||||||
|
return new EhCacheBasedAclCache(getCache(),
|
||||||
|
new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()),
|
||||||
|
new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_USER")));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void emptyDatabase() {
|
||||||
|
String query = "DELETE FROM acl_entry;" + "DELETE FROM acl_object_identity WHERE ID = 9;"
|
||||||
|
+ "DELETE FROM acl_object_identity WHERE ID = 8;" + "DELETE FROM acl_object_identity WHERE ID = 7;"
|
||||||
|
+ "DELETE FROM acl_object_identity WHERE ID = 6;" + "DELETE FROM acl_object_identity WHERE ID = 5;"
|
||||||
|
+ "DELETE FROM acl_object_identity WHERE ID = 4;" + "DELETE FROM acl_object_identity WHERE ID = 3;"
|
||||||
|
+ "DELETE FROM acl_object_identity WHERE ID = 2;" + "DELETE FROM acl_object_identity WHERE ID = 1;"
|
||||||
|
+ "DELETE FROM acl_class;" + "DELETE FROM acl_sid;";
|
||||||
|
getJdbcTemplate().execute(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Ehcache getCache() {
|
||||||
|
Ehcache cache = cacheManager.getCache("basiclookuptestcache");
|
||||||
|
cache.removeAll();
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAclsRetrievalWithDefaultBatchSize() throws Exception {
|
||||||
|
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
|
||||||
|
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(101));
|
||||||
|
// Deliberately use an integer for the child, to reproduce bug report in SEC-819
|
||||||
|
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, Integer.valueOf(102));
|
||||||
|
|
||||||
|
Map<ObjectIdentity, Acl> map = this.strategy
|
||||||
|
.readAclsById(Arrays.asList(topParentOid, middleParentOid, childOid), null);
|
||||||
|
checkEntries(topParentOid, middleParentOid, childOid, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAclsRetrievalFromCacheOnly() throws Exception {
|
||||||
|
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, Integer.valueOf(100));
|
||||||
|
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(101));
|
||||||
|
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(102));
|
||||||
|
|
||||||
|
// Objects were put in cache
|
||||||
|
strategy.readAclsById(Arrays.asList(topParentOid, middleParentOid, childOid), null);
|
||||||
|
|
||||||
|
// Let's empty the database to force acls retrieval from cache
|
||||||
|
emptyDatabase();
|
||||||
|
Map<ObjectIdentity, Acl> map = this.strategy
|
||||||
|
.readAclsById(Arrays.asList(topParentOid, middleParentOid, childOid), null);
|
||||||
|
|
||||||
|
checkEntries(topParentOid, middleParentOid, childOid, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAclsRetrievalWithCustomBatchSize() throws Exception {
|
||||||
|
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
|
||||||
|
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, Integer.valueOf(101));
|
||||||
|
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(102));
|
||||||
|
|
||||||
|
// Set a batch size to allow multiple database queries in order to retrieve all
|
||||||
|
// acls
|
||||||
|
this.strategy.setBatchSize(1);
|
||||||
|
Map<ObjectIdentity, Acl> map = this.strategy
|
||||||
|
.readAclsById(Arrays.asList(topParentOid, middleParentOid, childOid), null);
|
||||||
|
checkEntries(topParentOid, middleParentOid, childOid, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkEntries(ObjectIdentity topParentOid, ObjectIdentity middleParentOid, ObjectIdentity childOid,
|
||||||
|
Map<ObjectIdentity, Acl> map) throws Exception {
|
||||||
|
assertThat(map).hasSize(3);
|
||||||
|
|
||||||
|
MutableAcl topParent = (MutableAcl) map.get(topParentOid);
|
||||||
|
MutableAcl middleParent = (MutableAcl) map.get(middleParentOid);
|
||||||
|
MutableAcl child = (MutableAcl) map.get(childOid);
|
||||||
|
|
||||||
|
// Check the retrieved versions has IDs
|
||||||
|
assertThat(topParent.getId()).isNotNull();
|
||||||
|
assertThat(middleParent.getId()).isNotNull();
|
||||||
|
assertThat(child.getId()).isNotNull();
|
||||||
|
|
||||||
|
// Check their parents were correctly retrieved
|
||||||
|
assertThat(topParent.getParentAcl()).isNull();
|
||||||
|
assertThat(middleParent.getParentAcl().getObjectIdentity()).isEqualTo(topParentOid);
|
||||||
|
assertThat(child.getParentAcl().getObjectIdentity()).isEqualTo(middleParentOid);
|
||||||
|
|
||||||
|
// Check their ACEs were correctly retrieved
|
||||||
|
assertThat(topParent.getEntries()).hasSize(2);
|
||||||
|
assertThat(middleParent.getEntries()).hasSize(1);
|
||||||
|
assertThat(child.getEntries()).hasSize(1);
|
||||||
|
|
||||||
|
// Check object identities were correctly retrieved
|
||||||
|
assertThat(topParent.getObjectIdentity()).isEqualTo(topParentOid);
|
||||||
|
assertThat(middleParent.getObjectIdentity()).isEqualTo(middleParentOid);
|
||||||
|
assertThat(child.getObjectIdentity()).isEqualTo(childOid);
|
||||||
|
|
||||||
|
// Check each entry
|
||||||
|
assertThat(topParent.isEntriesInheriting()).isTrue();
|
||||||
|
assertThat(Long.valueOf(1)).isEqualTo(topParent.getId());
|
||||||
|
assertThat(new PrincipalSid("ben")).isEqualTo(topParent.getOwner());
|
||||||
|
assertThat(Long.valueOf(1)).isEqualTo(topParent.getEntries().get(0).getId());
|
||||||
|
assertThat(topParent.getEntries().get(0).getPermission()).isEqualTo(BasePermission.READ);
|
||||||
|
assertThat(topParent.getEntries().get(0).getSid()).isEqualTo(new PrincipalSid("ben"));
|
||||||
|
assertThat(((AuditableAccessControlEntry) topParent.getEntries().get(0)).isAuditFailure()).isFalse();
|
||||||
|
assertThat(((AuditableAccessControlEntry) topParent.getEntries().get(0)).isAuditSuccess()).isFalse();
|
||||||
|
assertThat((topParent.getEntries().get(0)).isGranting()).isTrue();
|
||||||
|
|
||||||
|
assertThat(Long.valueOf(2)).isEqualTo(topParent.getEntries().get(1).getId());
|
||||||
|
assertThat(topParent.getEntries().get(1).getPermission()).isEqualTo(BasePermission.WRITE);
|
||||||
|
assertThat(topParent.getEntries().get(1).getSid()).isEqualTo(new PrincipalSid("ben"));
|
||||||
|
assertThat(((AuditableAccessControlEntry) topParent.getEntries().get(1)).isAuditFailure()).isFalse();
|
||||||
|
assertThat(((AuditableAccessControlEntry) topParent.getEntries().get(1)).isAuditSuccess()).isFalse();
|
||||||
|
assertThat(topParent.getEntries().get(1).isGranting()).isFalse();
|
||||||
|
|
||||||
|
assertThat(middleParent.isEntriesInheriting()).isTrue();
|
||||||
|
assertThat(Long.valueOf(2)).isEqualTo(middleParent.getId());
|
||||||
|
assertThat(new PrincipalSid("ben")).isEqualTo(middleParent.getOwner());
|
||||||
|
assertThat(Long.valueOf(3)).isEqualTo(middleParent.getEntries().get(0).getId());
|
||||||
|
assertThat(middleParent.getEntries().get(0).getPermission()).isEqualTo(BasePermission.DELETE);
|
||||||
|
assertThat(middleParent.getEntries().get(0).getSid()).isEqualTo(new PrincipalSid("ben"));
|
||||||
|
assertThat(((AuditableAccessControlEntry) middleParent.getEntries().get(0)).isAuditFailure()).isFalse();
|
||||||
|
assertThat(((AuditableAccessControlEntry) middleParent.getEntries().get(0)).isAuditSuccess()).isFalse();
|
||||||
|
assertThat(middleParent.getEntries().get(0).isGranting()).isTrue();
|
||||||
|
|
||||||
|
assertThat(child.isEntriesInheriting()).isTrue();
|
||||||
|
assertThat(Long.valueOf(3)).isEqualTo(child.getId());
|
||||||
|
assertThat(new PrincipalSid("ben")).isEqualTo(child.getOwner());
|
||||||
|
assertThat(Long.valueOf(4)).isEqualTo(child.getEntries().get(0).getId());
|
||||||
|
assertThat(child.getEntries().get(0).getPermission()).isEqualTo(BasePermission.DELETE);
|
||||||
|
assertThat(new PrincipalSid("ben")).isEqualTo(child.getEntries().get(0).getSid());
|
||||||
|
assertThat(((AuditableAccessControlEntry) child.getEntries().get(0)).isAuditFailure()).isFalse();
|
||||||
|
assertThat(((AuditableAccessControlEntry) child.getEntries().get(0)).isAuditSuccess()).isFalse();
|
||||||
|
assertThat((child.getEntries().get(0)).isGranting()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAllParentsAreRetrievedWhenChildIsLoaded() throws Exception {
|
||||||
|
String query = "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (6,2,103,1,1,1);";
|
||||||
|
getJdbcTemplate().execute(query);
|
||||||
|
|
||||||
|
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(100));
|
||||||
|
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(101));
|
||||||
|
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(102));
|
||||||
|
ObjectIdentity middleParent2Oid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(103));
|
||||||
|
|
||||||
|
// Retrieve the child
|
||||||
|
Map<ObjectIdentity, Acl> map = this.strategy.readAclsById(Arrays.asList(childOid), null);
|
||||||
|
|
||||||
|
// Check that the child and all its parents were retrieved
|
||||||
|
assertThat(map.get(childOid)).isNotNull();
|
||||||
|
assertThat(map.get(childOid).getObjectIdentity()).isEqualTo(childOid);
|
||||||
|
assertThat(map.get(middleParentOid)).isNotNull();
|
||||||
|
assertThat(map.get(middleParentOid).getObjectIdentity()).isEqualTo(middleParentOid);
|
||||||
|
assertThat(map.get(topParentOid)).isNotNull();
|
||||||
|
assertThat(map.get(topParentOid).getObjectIdentity()).isEqualTo(topParentOid);
|
||||||
|
|
||||||
|
// The second parent shouldn't have been retrieved
|
||||||
|
assertThat(map.get(middleParent2Oid)).isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test created from SEC-590.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testReadAllObjectIdentitiesWhenLastElementIsAlreadyCached() throws Exception {
|
||||||
|
String query = "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (6,2,105,null,1,1);"
|
||||||
|
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (7,2,106,6,1,1);"
|
||||||
|
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (8,2,107,6,1,1);"
|
||||||
|
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (9,2,108,7,1,1);"
|
||||||
|
+ "INSERT INTO acl_entry(ID,ACL_OBJECT_IDENTITY,ACE_ORDER,SID,MASK,GRANTING,AUDIT_SUCCESS,AUDIT_FAILURE) VALUES (7,6,0,1,1,1,0,0)";
|
||||||
|
getJdbcTemplate().execute(query);
|
||||||
|
|
||||||
|
ObjectIdentity grandParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(104));
|
||||||
|
ObjectIdentity parent1Oid = new ObjectIdentityImpl(TARGET_CLASS, new Long(105));
|
||||||
|
ObjectIdentity parent2Oid = new ObjectIdentityImpl(TARGET_CLASS, Integer.valueOf(106));
|
||||||
|
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, Integer.valueOf(107));
|
||||||
|
|
||||||
|
// First lookup only child, thus populating the cache with grandParent,
|
||||||
|
// parent1
|
||||||
|
// and child
|
||||||
|
List<Permission> checkPermission = Arrays.asList(BasePermission.READ);
|
||||||
|
List<Sid> sids = Arrays.asList(BEN_SID);
|
||||||
|
List<ObjectIdentity> childOids = Arrays.asList(childOid);
|
||||||
|
|
||||||
|
strategy.setBatchSize(6);
|
||||||
|
Map<ObjectIdentity, Acl> foundAcls = strategy.readAclsById(childOids, sids);
|
||||||
|
|
||||||
|
Acl foundChildAcl = foundAcls.get(childOid);
|
||||||
|
assertThat(foundChildAcl).isNotNull();
|
||||||
|
assertThat(foundChildAcl.isGranted(checkPermission, sids, false)).isTrue();
|
||||||
|
|
||||||
|
// Search for object identities has to be done in the following order:
|
||||||
|
// last
|
||||||
|
// element have to be one which
|
||||||
|
// is already in cache and the element before it must not be stored in
|
||||||
|
// cache
|
||||||
|
List<ObjectIdentity> allOids = Arrays.asList(grandParentOid, parent1Oid, parent2Oid, childOid);
|
||||||
|
try {
|
||||||
|
foundAcls = strategy.readAclsById(allOids, sids);
|
||||||
|
|
||||||
|
} catch (NotFoundException notExpected) {
|
||||||
|
fail("It shouldn't have thrown NotFoundException");
|
||||||
|
}
|
||||||
|
|
||||||
|
Acl foundParent2Acl = foundAcls.get(parent2Oid);
|
||||||
|
assertThat(foundParent2Acl).isNotNull();
|
||||||
|
assertThat(foundParent2Acl.isGranted(checkPermission, sids, false)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void nullOwnerIsNotSupported() {
|
||||||
|
String query = "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (6,2,104,null,null,1);";
|
||||||
|
|
||||||
|
getJdbcTemplate().execute(query);
|
||||||
|
|
||||||
|
ObjectIdentity oid = new ObjectIdentityImpl(TARGET_CLASS, new Long(104));
|
||||||
|
|
||||||
|
strategy.readAclsById(Arrays.asList(oid), Arrays.asList(BEN_SID));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreatePrincipalSid() {
|
||||||
|
Sid result = strategy.createSid(true, "sid");
|
||||||
|
|
||||||
|
assertThat(result.getClass()).isEqualTo(PrincipalSid.class);
|
||||||
|
assertThat(((PrincipalSid) result).getPrincipal()).isEqualTo("sid");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateGrantedAuthority() {
|
||||||
|
Sid result = strategy.createSid(false, "sid");
|
||||||
|
|
||||||
|
assertThat(result.getClass()).isEqualTo(GrantedAuthoritySid.class);
|
||||||
|
assertThat(((GrantedAuthoritySid) result).getGrantedAuthority()).isEqualTo("sid");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2017 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.security.acls.jdbc;
|
||||||
|
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.BDDMockito.given;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.runners.MockitoJUnitRunner;
|
||||||
|
import org.springframework.core.convert.ConversionService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link AclClassIdUtils}.
|
||||||
|
* @author paulwheeler
|
||||||
|
*/
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class AclClassIdUtilsTest {
|
||||||
|
|
||||||
|
private static final Long DEFAULT_IDENTIFIER = 999L;
|
||||||
|
private static final String DEFAULT_IDENTIFIER_AS_STRING = DEFAULT_IDENTIFIER.toString();
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ResultSet resultSet;
|
||||||
|
@Mock
|
||||||
|
private ConversionService conversionService;
|
||||||
|
@InjectMocks
|
||||||
|
private AclClassIdUtils aclClassIdUtils;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
given(conversionService.canConvert(String.class, Long.class)).willReturn(true);
|
||||||
|
given(conversionService.convert(DEFAULT_IDENTIFIER, Long.class)).willReturn(new Long(DEFAULT_IDENTIFIER));
|
||||||
|
given(conversionService.convert(DEFAULT_IDENTIFIER_AS_STRING, Long.class)).willReturn(new Long(DEFAULT_IDENTIFIER));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnLongIfIdentifierIsNotStringAndNoConversionService() throws SQLException {
|
||||||
|
// given
|
||||||
|
AclClassIdUtils aclClassIdUtilsWithoutConversionSvc = new AclClassIdUtils();
|
||||||
|
|
||||||
|
// when
|
||||||
|
Serializable newIdentifier = aclClassIdUtilsWithoutConversionSvc.identifierFrom(DEFAULT_IDENTIFIER, resultSet);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(newIdentifier).isEqualTo(DEFAULT_IDENTIFIER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnLongIfIdentifierIsNotString() throws SQLException {
|
||||||
|
// given
|
||||||
|
Long prevIdentifier = 999L;
|
||||||
|
|
||||||
|
// when
|
||||||
|
Serializable newIdentifier = aclClassIdUtils.identifierFrom(prevIdentifier, resultSet);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(newIdentifier).isEqualTo(prevIdentifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnLongIfClassIdTypeIsNull() throws SQLException {
|
||||||
|
// given
|
||||||
|
given(resultSet.getString("class_id_type")).willReturn(null);
|
||||||
|
|
||||||
|
// when
|
||||||
|
Serializable newIdentifier = aclClassIdUtils.identifierFrom(DEFAULT_IDENTIFIER_AS_STRING, resultSet);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(newIdentifier).isEqualTo(DEFAULT_IDENTIFIER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnLongIfNoClassIdTypeColumn() throws SQLException {
|
||||||
|
// given
|
||||||
|
given(resultSet.getString("class_id_type")).willThrow(SQLException.class);
|
||||||
|
|
||||||
|
// when
|
||||||
|
Serializable newIdentifier = aclClassIdUtils.identifierFrom(DEFAULT_IDENTIFIER_AS_STRING, resultSet);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(newIdentifier).isEqualTo(DEFAULT_IDENTIFIER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnLongIfTypeClassNotFound() throws SQLException {
|
||||||
|
// given
|
||||||
|
given(resultSet.getString("class_id_type")).willReturn("com.example.UnknownType");
|
||||||
|
|
||||||
|
// when
|
||||||
|
Serializable newIdentifier = aclClassIdUtils.identifierFrom(DEFAULT_IDENTIFIER_AS_STRING, resultSet);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(newIdentifier).isEqualTo(DEFAULT_IDENTIFIER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnLongIfTypeClassCannotBeConverted() throws SQLException {
|
||||||
|
// given
|
||||||
|
given(resultSet.getString("class_id_type")).willReturn("java.lang.Long");
|
||||||
|
given(conversionService.canConvert(String.class, Long.class)).willReturn(false);
|
||||||
|
|
||||||
|
// when
|
||||||
|
Serializable newIdentifier = aclClassIdUtils.identifierFrom(DEFAULT_IDENTIFIER_AS_STRING, resultSet);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(newIdentifier).isEqualTo(DEFAULT_IDENTIFIER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnLongWhenLongClassIdType() throws SQLException {
|
||||||
|
// given
|
||||||
|
given(resultSet.getString("class_id_type")).willReturn("java.lang.Long");
|
||||||
|
|
||||||
|
// when
|
||||||
|
Serializable newIdentifier = aclClassIdUtils.identifierFrom(DEFAULT_IDENTIFIER_AS_STRING, resultSet);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(newIdentifier).isEqualTo(DEFAULT_IDENTIFIER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnUUIDWhenUUIDClassIdType() throws SQLException {
|
||||||
|
// given
|
||||||
|
UUID identifier = UUID.randomUUID();
|
||||||
|
String identifierAsString = identifier.toString();
|
||||||
|
given(resultSet.getString("class_id_type")).willReturn("java.util.UUID");
|
||||||
|
given(conversionService.canConvert(String.class, UUID.class)).willReturn(true);
|
||||||
|
given(conversionService.convert(identifierAsString, UUID.class)).willReturn(UUID.fromString(identifierAsString));
|
||||||
|
|
||||||
|
// when
|
||||||
|
Serializable newIdentifier = aclClassIdUtils.identifierFrom(identifier.toString(), resultSet);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(newIdentifier).isEqualTo(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2017 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -15,330 +15,39 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.security.acls.jdbc;
|
package org.springframework.security.acls.jdbc;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.*;
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
import net.sf.ehcache.Cache;
|
import org.junit.AfterClass;
|
||||||
import net.sf.ehcache.CacheManager;
|
import org.junit.BeforeClass;
|
||||||
import net.sf.ehcache.Ehcache;
|
|
||||||
import org.junit.*;
|
|
||||||
import org.springframework.core.io.ClassPathResource;
|
|
||||||
import org.springframework.core.io.Resource;
|
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.jdbc.datasource.SingleConnectionDataSource;
|
|
||||||
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;
|
|
||||||
import org.springframework.security.acls.model.NotFoundException;
|
|
||||||
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.core.authority.SimpleGrantedAuthority;
|
|
||||||
import org.springframework.util.FileCopyUtils;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link BasicLookupStrategy}
|
* Tests {@link BasicLookupStrategy} with Acl Class type id not specified.
|
||||||
*
|
*
|
||||||
* @author Andrei Stefan
|
* @author Andrei Stefan
|
||||||
|
* @author Paul Wheeler
|
||||||
*/
|
*/
|
||||||
public class BasicLookupStrategyTests {
|
public class BasicLookupStrategyTests extends AbstractBasicLookupStrategyTests {
|
||||||
|
private static final BasicLookupStrategyTestsDbHelper DATABASE_HELPER = new BasicLookupStrategyTestsDbHelper();
|
||||||
|
|
||||||
private static final Sid BEN_SID = new PrincipalSid("ben");
|
|
||||||
private static final String TARGET_CLASS = "org.springframework.security.acls.TargetObject";
|
|
||||||
|
|
||||||
// ~ Instance fields
|
|
||||||
// ================================================================================================
|
|
||||||
|
|
||||||
private static JdbcTemplate jdbcTemplate;
|
|
||||||
private BasicLookupStrategy strategy;
|
|
||||||
private static SingleConnectionDataSource dataSource;
|
|
||||||
private static CacheManager cacheManager;
|
|
||||||
|
|
||||||
// ~ Methods
|
|
||||||
// ========================================================================================================
|
|
||||||
@BeforeClass
|
|
||||||
public static void initCacheManaer() {
|
|
||||||
cacheManager = CacheManager.create();
|
|
||||||
cacheManager.addCache(new Cache("basiclookuptestcache", 500, false, false, 30, 30));
|
|
||||||
}
|
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void createDatabase() throws Exception {
|
public static void createDatabase() throws Exception {
|
||||||
dataSource = new SingleConnectionDataSource("jdbc:hsqldb:mem:lookupstrategytest", "sa", "", true);
|
DATABASE_HELPER.createDatabase();
|
||||||
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
|
|
||||||
jdbcTemplate = new JdbcTemplate(dataSource);
|
|
||||||
|
|
||||||
Resource resource = new ClassPathResource("createAclSchema.sql");
|
|
||||||
String sql = new String(FileCopyUtils.copyToByteArray(resource.getInputStream()));
|
|
||||||
jdbcTemplate.execute(sql);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
public static void dropDatabase() throws Exception {
|
public static void dropDatabase() throws Exception {
|
||||||
dataSource.destroy();
|
DATABASE_HELPER.getDataSource().destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@Override
|
||||||
public static void shutdownCacheManager() {
|
public JdbcTemplate getJdbcTemplate() {
|
||||||
cacheManager.removalAll();
|
return DATABASE_HELPER.getJdbcTemplate();
|
||||||
cacheManager.shutdown();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Override
|
||||||
public void populateDatabase() {
|
public DataSource getDataSource() {
|
||||||
String query = "INSERT INTO acl_sid(ID,PRINCIPAL,SID) VALUES (1,1,'ben');"
|
return DATABASE_HELPER.getDataSource();
|
||||||
+ "INSERT INTO acl_class(ID,CLASS) VALUES (2,'" + TARGET_CLASS + "');"
|
|
||||||
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (1,2,100,null,1,1);"
|
|
||||||
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (2,2,101,1,1,1);"
|
|
||||||
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (3,2,102,2,1,1);"
|
|
||||||
+ "INSERT INTO acl_entry(ID,ACL_OBJECT_IDENTITY,ACE_ORDER,SID,MASK,GRANTING,AUDIT_SUCCESS,AUDIT_FAILURE) VALUES (1,1,0,1,1,1,0,0);"
|
|
||||||
+ "INSERT INTO acl_entry(ID,ACL_OBJECT_IDENTITY,ACE_ORDER,SID,MASK,GRANTING,AUDIT_SUCCESS,AUDIT_FAILURE) VALUES (2,1,1,1,2,0,0,0);"
|
|
||||||
+ "INSERT INTO acl_entry(ID,ACL_OBJECT_IDENTITY,ACE_ORDER,SID,MASK,GRANTING,AUDIT_SUCCESS,AUDIT_FAILURE) VALUES (3,2,0,1,8,1,0,0);"
|
|
||||||
+ "INSERT INTO acl_entry(ID,ACL_OBJECT_IDENTITY,ACE_ORDER,SID,MASK,GRANTING,AUDIT_SUCCESS,AUDIT_FAILURE) VALUES (4,3,0,1,8,0,0,0);";
|
|
||||||
jdbcTemplate.execute(query);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
|
||||||
public void initializeBeans() {
|
|
||||||
EhCacheBasedAclCache cache = new EhCacheBasedAclCache(getCache(),
|
|
||||||
new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()),
|
|
||||||
new AclAuthorizationStrategyImpl(new SimpleGrantedAuthority("ROLE_USER")));
|
|
||||||
AclAuthorizationStrategy authorizationStrategy = new AclAuthorizationStrategyImpl(
|
|
||||||
new SimpleGrantedAuthority("ROLE_ADMINISTRATOR"));
|
|
||||||
strategy = new BasicLookupStrategy(dataSource, cache, authorizationStrategy,
|
|
||||||
new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()));
|
|
||||||
strategy.setPermissionFactory(new DefaultPermissionFactory());
|
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void emptyDatabase() {
|
|
||||||
String query = "DELETE FROM acl_entry;" + "DELETE FROM acl_object_identity WHERE ID = 7;"
|
|
||||||
+ "DELETE FROM acl_object_identity WHERE ID = 6;" + "DELETE FROM acl_object_identity WHERE ID = 5;"
|
|
||||||
+ "DELETE FROM acl_object_identity WHERE ID = 4;" + "DELETE FROM acl_object_identity WHERE ID = 3;"
|
|
||||||
+ "DELETE FROM acl_object_identity WHERE ID = 2;" + "DELETE FROM acl_object_identity WHERE ID = 1;"
|
|
||||||
+ "DELETE FROM acl_class;" + "DELETE FROM acl_sid;";
|
|
||||||
jdbcTemplate.execute(query);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Ehcache getCache() {
|
|
||||||
Ehcache cache = cacheManager.getCache("basiclookuptestcache");
|
|
||||||
cache.removeAll();
|
|
||||||
return cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testAclsRetrievalWithDefaultBatchSize() throws Exception {
|
|
||||||
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
|
|
||||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(101));
|
|
||||||
// Deliberately use an integer for the child, to reproduce bug report in
|
|
||||||
// SEC-819
|
|
||||||
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, Integer.valueOf(102));
|
|
||||||
|
|
||||||
Map<ObjectIdentity, Acl> map = this.strategy
|
|
||||||
.readAclsById(Arrays.asList(topParentOid, middleParentOid, childOid), null);
|
|
||||||
checkEntries(topParentOid, middleParentOid, childOid, map);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testAclsRetrievalFromCacheOnly() throws Exception {
|
|
||||||
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, Integer.valueOf(100));
|
|
||||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(101));
|
|
||||||
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(102));
|
|
||||||
|
|
||||||
// Objects were put in cache
|
|
||||||
strategy.readAclsById(Arrays.asList(topParentOid, middleParentOid, childOid), null);
|
|
||||||
|
|
||||||
// Let's empty the database to force acls retrieval from cache
|
|
||||||
emptyDatabase();
|
|
||||||
Map<ObjectIdentity, Acl> map = this.strategy
|
|
||||||
.readAclsById(Arrays.asList(topParentOid, middleParentOid, childOid), null);
|
|
||||||
|
|
||||||
checkEntries(topParentOid, middleParentOid, childOid, map);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testAclsRetrievalWithCustomBatchSize() throws Exception {
|
|
||||||
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
|
|
||||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, Integer.valueOf(101));
|
|
||||||
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(102));
|
|
||||||
|
|
||||||
// Set a batch size to allow multiple database queries in order to
|
|
||||||
// retrieve all
|
|
||||||
// acls
|
|
||||||
this.strategy.setBatchSize(1);
|
|
||||||
Map<ObjectIdentity, Acl> map = this.strategy
|
|
||||||
.readAclsById(Arrays.asList(topParentOid, middleParentOid, childOid), null);
|
|
||||||
checkEntries(topParentOid, middleParentOid, childOid, map);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkEntries(ObjectIdentity topParentOid, ObjectIdentity middleParentOid, ObjectIdentity childOid,
|
|
||||||
Map<ObjectIdentity, Acl> map) throws Exception {
|
|
||||||
assertThat(map).hasSize(3);
|
|
||||||
|
|
||||||
MutableAcl topParent = (MutableAcl) map.get(topParentOid);
|
|
||||||
MutableAcl middleParent = (MutableAcl) map.get(middleParentOid);
|
|
||||||
MutableAcl child = (MutableAcl) map.get(childOid);
|
|
||||||
|
|
||||||
// Check the retrieved versions has IDs
|
|
||||||
assertThat(topParent.getId()).isNotNull();
|
|
||||||
assertThat(middleParent.getId()).isNotNull();
|
|
||||||
assertThat(child.getId()).isNotNull();
|
|
||||||
|
|
||||||
// Check their parents were correctly retrieved
|
|
||||||
assertThat(topParent.getParentAcl()).isNull();
|
|
||||||
assertThat(middleParent.getParentAcl().getObjectIdentity()).isEqualTo(topParentOid);
|
|
||||||
assertThat(child.getParentAcl().getObjectIdentity()).isEqualTo(middleParentOid);
|
|
||||||
|
|
||||||
// Check their ACEs were correctly retrieved
|
|
||||||
assertThat(topParent.getEntries()).hasSize(2);
|
|
||||||
assertThat(middleParent.getEntries()).hasSize(1);
|
|
||||||
assertThat(child.getEntries()).hasSize(1);
|
|
||||||
|
|
||||||
// Check object identities were correctly retrieved
|
|
||||||
assertThat(topParent.getObjectIdentity()).isEqualTo(topParentOid);
|
|
||||||
assertThat(middleParent.getObjectIdentity()).isEqualTo(middleParentOid);
|
|
||||||
assertThat(child.getObjectIdentity()).isEqualTo(childOid);
|
|
||||||
|
|
||||||
// Check each entry
|
|
||||||
assertThat(topParent.isEntriesInheriting()).isTrue();
|
|
||||||
assertThat(Long.valueOf(1)).isEqualTo(topParent.getId());
|
|
||||||
assertThat(new PrincipalSid("ben")).isEqualTo(topParent.getOwner());
|
|
||||||
assertThat(Long.valueOf(1)).isEqualTo(topParent.getEntries().get(0).getId());
|
|
||||||
assertThat(topParent.getEntries().get(0).getPermission()).isEqualTo(BasePermission.READ);
|
|
||||||
assertThat(topParent.getEntries().get(0).getSid()).isEqualTo(new PrincipalSid("ben"));
|
|
||||||
assertThat(((AuditableAccessControlEntry) topParent.getEntries().get(0)).isAuditFailure()).isFalse();
|
|
||||||
assertThat(((AuditableAccessControlEntry) topParent.getEntries().get(0)).isAuditSuccess()).isFalse();
|
|
||||||
assertThat((topParent.getEntries().get(0)).isGranting()).isTrue();
|
|
||||||
|
|
||||||
assertThat(Long.valueOf(2)).isEqualTo(topParent.getEntries().get(1).getId());
|
|
||||||
assertThat(topParent.getEntries().get(1).getPermission()).isEqualTo(BasePermission.WRITE);
|
|
||||||
assertThat(topParent.getEntries().get(1).getSid()).isEqualTo(new PrincipalSid("ben"));
|
|
||||||
assertThat(((AuditableAccessControlEntry) topParent.getEntries().get(1)).isAuditFailure()).isFalse();
|
|
||||||
assertThat(((AuditableAccessControlEntry) topParent.getEntries().get(1)).isAuditSuccess()).isFalse();
|
|
||||||
assertThat(topParent.getEntries().get(1).isGranting()).isFalse();
|
|
||||||
|
|
||||||
assertThat(middleParent.isEntriesInheriting()).isTrue();
|
|
||||||
assertThat(Long.valueOf(2)).isEqualTo(middleParent.getId());
|
|
||||||
assertThat(new PrincipalSid("ben")).isEqualTo(middleParent.getOwner());
|
|
||||||
assertThat(Long.valueOf(3)).isEqualTo(middleParent.getEntries().get(0).getId());
|
|
||||||
assertThat(middleParent.getEntries().get(0).getPermission()).isEqualTo(BasePermission.DELETE);
|
|
||||||
assertThat(middleParent.getEntries().get(0).getSid()).isEqualTo(new PrincipalSid("ben"));
|
|
||||||
assertThat(((AuditableAccessControlEntry) middleParent.getEntries().get(0)).isAuditFailure()).isFalse();
|
|
||||||
assertThat(((AuditableAccessControlEntry) middleParent.getEntries().get(0)).isAuditSuccess()).isFalse();
|
|
||||||
assertThat(middleParent.getEntries().get(0).isGranting()).isTrue();
|
|
||||||
|
|
||||||
assertThat(child.isEntriesInheriting()).isTrue();
|
|
||||||
assertThat(Long.valueOf(3)).isEqualTo(child.getId());
|
|
||||||
assertThat(new PrincipalSid("ben")).isEqualTo(child.getOwner());
|
|
||||||
assertThat(Long.valueOf(4)).isEqualTo(child.getEntries().get(0).getId());
|
|
||||||
assertThat(child.getEntries().get(0).getPermission()).isEqualTo(BasePermission.DELETE);
|
|
||||||
assertThat(new PrincipalSid("ben")).isEqualTo(child.getEntries().get(0).getSid());
|
|
||||||
assertThat(((AuditableAccessControlEntry) child.getEntries().get(0)).isAuditFailure()).isFalse();
|
|
||||||
assertThat(((AuditableAccessControlEntry) child.getEntries().get(0)).isAuditSuccess()).isFalse();
|
|
||||||
assertThat((child.getEntries().get(0)).isGranting()).isFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testAllParentsAreRetrievedWhenChildIsLoaded() throws Exception {
|
|
||||||
String query = "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (4,2,103,1,1,1);";
|
|
||||||
jdbcTemplate.execute(query);
|
|
||||||
|
|
||||||
ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(100));
|
|
||||||
ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(101));
|
|
||||||
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(102));
|
|
||||||
ObjectIdentity middleParent2Oid = new ObjectIdentityImpl(TARGET_CLASS, Long.valueOf(103));
|
|
||||||
|
|
||||||
// Retrieve the child
|
|
||||||
Map<ObjectIdentity, Acl> map = this.strategy.readAclsById(Arrays.asList(childOid), null);
|
|
||||||
|
|
||||||
// Check that the child and all its parents were retrieved
|
|
||||||
assertThat(map.get(childOid)).isNotNull();
|
|
||||||
assertThat(map.get(childOid).getObjectIdentity()).isEqualTo(childOid);
|
|
||||||
assertThat(map.get(middleParentOid)).isNotNull();
|
|
||||||
assertThat(map.get(middleParentOid).getObjectIdentity()).isEqualTo(middleParentOid);
|
|
||||||
assertThat(map.get(topParentOid)).isNotNull();
|
|
||||||
assertThat(map.get(topParentOid).getObjectIdentity()).isEqualTo(topParentOid);
|
|
||||||
|
|
||||||
// The second parent shouldn't have been retrieved
|
|
||||||
assertThat(map.get(middleParent2Oid)).isNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test created from SEC-590.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testReadAllObjectIdentitiesWhenLastElementIsAlreadyCached() throws Exception {
|
|
||||||
String query = "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (4,2,104,null,1,1);"
|
|
||||||
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (5,2,105,4,1,1);"
|
|
||||||
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (6,2,106,4,1,1);"
|
|
||||||
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (7,2,107,5,1,1);"
|
|
||||||
+ "INSERT INTO acl_entry(ID,ACL_OBJECT_IDENTITY,ACE_ORDER,SID,MASK,GRANTING,AUDIT_SUCCESS,AUDIT_FAILURE) VALUES (5,4,0,1,1,1,0,0)";
|
|
||||||
jdbcTemplate.execute(query);
|
|
||||||
|
|
||||||
ObjectIdentity grandParentOid = new ObjectIdentityImpl(TARGET_CLASS, new Long(104));
|
|
||||||
ObjectIdentity parent1Oid = new ObjectIdentityImpl(TARGET_CLASS, new Long(105));
|
|
||||||
ObjectIdentity parent2Oid = new ObjectIdentityImpl(TARGET_CLASS, Integer.valueOf(106));
|
|
||||||
ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS, Integer.valueOf(107));
|
|
||||||
|
|
||||||
// First lookup only child, thus populating the cache with grandParent,
|
|
||||||
// parent1
|
|
||||||
// and child
|
|
||||||
List<Permission> checkPermission = Arrays.asList(BasePermission.READ);
|
|
||||||
List<Sid> sids = Arrays.asList(BEN_SID);
|
|
||||||
List<ObjectIdentity> childOids = Arrays.asList(childOid);
|
|
||||||
|
|
||||||
strategy.setBatchSize(6);
|
|
||||||
Map<ObjectIdentity, Acl> foundAcls = strategy.readAclsById(childOids, sids);
|
|
||||||
|
|
||||||
Acl foundChildAcl = foundAcls.get(childOid);
|
|
||||||
assertThat(foundChildAcl).isNotNull();
|
|
||||||
assertThat(foundChildAcl.isGranted(checkPermission, sids, false)).isTrue();
|
|
||||||
|
|
||||||
// Search for object identities has to be done in the following order:
|
|
||||||
// last
|
|
||||||
// element have to be one which
|
|
||||||
// is already in cache and the element before it must not be stored in
|
|
||||||
// cache
|
|
||||||
List<ObjectIdentity> allOids = Arrays.asList(grandParentOid, parent1Oid, parent2Oid, childOid);
|
|
||||||
try {
|
|
||||||
foundAcls = strategy.readAclsById(allOids, sids);
|
|
||||||
|
|
||||||
} catch (NotFoundException notExpected) {
|
|
||||||
fail("It shouldn't have thrown NotFoundException");
|
|
||||||
}
|
|
||||||
|
|
||||||
Acl foundParent2Acl = foundAcls.get(parent2Oid);
|
|
||||||
assertThat(foundParent2Acl).isNotNull();
|
|
||||||
assertThat(foundParent2Acl.isGranted(checkPermission, sids, false)).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
|
||||||
public void nullOwnerIsNotSupported() {
|
|
||||||
String query = "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (4,2,104,null,null,1);";
|
|
||||||
|
|
||||||
jdbcTemplate.execute(query);
|
|
||||||
|
|
||||||
ObjectIdentity oid = new ObjectIdentityImpl(TARGET_CLASS, new Long(104));
|
|
||||||
|
|
||||||
strategy.readAclsById(Arrays.asList(oid), Arrays.asList(BEN_SID));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCreatePrincipalSid() {
|
|
||||||
Sid result = strategy.createSid(true, "sid");
|
|
||||||
|
|
||||||
assertThat(result.getClass()).isEqualTo(PrincipalSid.class);
|
|
||||||
assertThat(((PrincipalSid) result).getPrincipal()).isEqualTo("sid");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCreateGrantedAuthority() {
|
|
||||||
Sid result = strategy.createSid(false, "sid");
|
|
||||||
|
|
||||||
assertThat(result.getClass()).isEqualTo(GrantedAuthoritySid.class);
|
|
||||||
assertThat(((GrantedAuthoritySid) result).getGrantedAuthority()).isEqualTo("sid");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2017 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.security.acls.jdbc;
|
||||||
|
|
||||||
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
import org.springframework.jdbc.datasource.SingleConnectionDataSource;
|
||||||
|
import org.springframework.util.FileCopyUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class to initialize the database for BasicLookupStrategyTests.
|
||||||
|
* @author Andrei Stefan
|
||||||
|
* @author Paul Wheeler
|
||||||
|
*/
|
||||||
|
public class BasicLookupStrategyTestsDbHelper {
|
||||||
|
private static final String ACL_SCHEMA_SQL_FILE = "createAclSchema.sql";
|
||||||
|
private static final String ACL_SCHEMA_SQL_FILE_WITH_ACL_CLASS_ID = "createAclSchemaWithAclClassIdType.sql";
|
||||||
|
|
||||||
|
private SingleConnectionDataSource dataSource;
|
||||||
|
private JdbcTemplate jdbcTemplate;
|
||||||
|
private boolean withAclClassIdType;
|
||||||
|
|
||||||
|
public BasicLookupStrategyTestsDbHelper() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public BasicLookupStrategyTestsDbHelper(boolean withAclClassIdType) {
|
||||||
|
this.withAclClassIdType = withAclClassIdType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createDatabase() throws Exception {
|
||||||
|
// Use a different connection url so the tests can run in parallel
|
||||||
|
String connectionUrl;
|
||||||
|
String sqlClassPathResource;
|
||||||
|
if (!withAclClassIdType) {
|
||||||
|
connectionUrl = "jdbc:hsqldb:mem:lookupstrategytest";
|
||||||
|
sqlClassPathResource = ACL_SCHEMA_SQL_FILE;
|
||||||
|
} else {
|
||||||
|
connectionUrl = "jdbc:hsqldb:mem:lookupstrategytestWithAclClassIdType";
|
||||||
|
sqlClassPathResource = ACL_SCHEMA_SQL_FILE_WITH_ACL_CLASS_ID;
|
||||||
|
|
||||||
|
}
|
||||||
|
dataSource = new SingleConnectionDataSource(connectionUrl, "sa", "", true);
|
||||||
|
dataSource.setDriverClassName("org.hsqldb.jdbcDriver");
|
||||||
|
jdbcTemplate = new JdbcTemplate(dataSource);
|
||||||
|
|
||||||
|
Resource resource = new ClassPathResource(sqlClassPathResource);
|
||||||
|
String sql = new String(FileCopyUtils.copyToByteArray(resource.getInputStream()));
|
||||||
|
jdbcTemplate.execute(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JdbcTemplate getJdbcTemplate() {
|
||||||
|
return jdbcTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SingleConnectionDataSource getDataSource() {
|
||||||
|
return dataSource;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2017 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.security.acls.jdbc;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.core.convert.ConversionFailedException;
|
||||||
|
import org.springframework.core.convert.support.DefaultConversionService;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
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.ObjectIdentityImpl;
|
||||||
|
import org.springframework.security.acls.model.Acl;
|
||||||
|
import org.springframework.security.acls.model.ObjectIdentity;
|
||||||
|
|
||||||
|
import junit.framework.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests {@link BasicLookupStrategy} with Acl Class type id set to UUID.
|
||||||
|
*
|
||||||
|
* @author Paul Wheeler
|
||||||
|
*/
|
||||||
|
public class BasicLookupStrategyWithAclClassTypeTests extends AbstractBasicLookupStrategyTests {
|
||||||
|
|
||||||
|
private static final BasicLookupStrategyTestsDbHelper DATABASE_HELPER = new BasicLookupStrategyTestsDbHelper(true);
|
||||||
|
|
||||||
|
private BasicLookupStrategy uuidEnabledStrategy;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JdbcTemplate getJdbcTemplate() {
|
||||||
|
return DATABASE_HELPER.getJdbcTemplate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataSource getDataSource() {
|
||||||
|
return DATABASE_HELPER.getDataSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void createDatabase() throws Exception {
|
||||||
|
DATABASE_HELPER.createDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void dropDatabase() throws Exception {
|
||||||
|
DATABASE_HELPER.getDataSource().destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void initializeBeans() {
|
||||||
|
super.initializeBeans();
|
||||||
|
AclClassIdUtils aclClassIdUtils = new AclClassIdUtils();
|
||||||
|
aclClassIdUtils.setConversionService(new DefaultConversionService());
|
||||||
|
uuidEnabledStrategy = new BasicLookupStrategy(getDataSource(), aclCache(), aclAuthStrategy(),
|
||||||
|
new DefaultPermissionGrantingStrategy(new ConsoleAuditLogger()));
|
||||||
|
uuidEnabledStrategy.setPermissionFactory(new DefaultPermissionFactory());
|
||||||
|
uuidEnabledStrategy.setAclClassIdSupported(true);
|
||||||
|
uuidEnabledStrategy.setAclClassIdUtils(aclClassIdUtils);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void populateDatabaseForAclClassTypeTests() {
|
||||||
|
String query = "INSERT INTO acl_class(ID,CLASS,CLASS_ID_TYPE) VALUES (3,'"
|
||||||
|
+ TARGET_CLASS_WITH_UUID
|
||||||
|
+ "', 'java.util.UUID');"
|
||||||
|
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (4,3,'"
|
||||||
|
+ OBJECT_IDENTITY_UUID.toString() + "',null,1,1);"
|
||||||
|
+ "INSERT INTO acl_object_identity(ID,OBJECT_ID_CLASS,OBJECT_ID_IDENTITY,PARENT_OBJECT,OWNER_SID,ENTRIES_INHERITING) VALUES (5,3,'"
|
||||||
|
+ OBJECT_IDENTITY_LONG_AS_UUID + "',null,1,1);"
|
||||||
|
+ "INSERT INTO acl_entry(ID,ACL_OBJECT_IDENTITY,ACE_ORDER,SID,MASK,GRANTING,AUDIT_SUCCESS,AUDIT_FAILURE) VALUES (5,4,0,1,8,0,0,0);"
|
||||||
|
+ "INSERT INTO acl_entry(ID,ACL_OBJECT_IDENTITY,ACE_ORDER,SID,MASK,GRANTING,AUDIT_SUCCESS,AUDIT_FAILURE) VALUES (6,5,0,1,8,0,0,0);";
|
||||||
|
DATABASE_HELPER.getJdbcTemplate().execute(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadObjectIdentityUsingUuidType() {
|
||||||
|
ObjectIdentity oid = new ObjectIdentityImpl(TARGET_CLASS_WITH_UUID, OBJECT_IDENTITY_UUID);
|
||||||
|
Map<ObjectIdentity, Acl> foundAcls = uuidEnabledStrategy.readAclsById(Arrays.asList(oid), Arrays.asList(BEN_SID));
|
||||||
|
Assert.assertEquals(1, foundAcls.size());
|
||||||
|
Assert.assertNotNull(foundAcls.get(oid));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadObjectIdentityUsingLongTypeWithConversionServiceEnabled() {
|
||||||
|
ObjectIdentity oid = new ObjectIdentityImpl(TARGET_CLASS, new Long(100));
|
||||||
|
Map<ObjectIdentity, Acl> foundAcls = uuidEnabledStrategy.readAclsById(Arrays.asList(oid), Arrays.asList(BEN_SID));
|
||||||
|
Assert.assertEquals(1, foundAcls.size());
|
||||||
|
Assert.assertNotNull(foundAcls.get(oid));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = ConversionFailedException.class)
|
||||||
|
public void testReadObjectIdentityUsingNonUuidInDatabase() {
|
||||||
|
ObjectIdentity oid = new ObjectIdentityImpl(TARGET_CLASS_WITH_UUID, OBJECT_IDENTITY_LONG_AS_UUID);
|
||||||
|
uuidEnabledStrategy.readAclsById(Arrays.asList(oid), Arrays.asList(BEN_SID));
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
|
* Copyright 2004, 2005, 2006, 2017 Acegi Technology Pty Limited
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -98,10 +98,30 @@ public class JdbcMutableAclServiceTests extends
|
|||||||
// ~ Methods
|
// ~ Methods
|
||||||
// ========================================================================================================
|
// ========================================================================================================
|
||||||
|
|
||||||
|
protected String getSqlClassPathResource() {
|
||||||
|
return "createAclSchema.sql";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ObjectIdentity getTopParentOid() {
|
||||||
|
return topParentOid;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ObjectIdentity getMiddleParentOid() {
|
||||||
|
return middleParentOid;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ObjectIdentity getChildOid() {
|
||||||
|
return childOid;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getTargetClass() {
|
||||||
|
return TARGET_CLASS;
|
||||||
|
}
|
||||||
|
|
||||||
@BeforeTransaction
|
@BeforeTransaction
|
||||||
public void createTables() throws Exception {
|
public void createTables() throws Exception {
|
||||||
try {
|
try {
|
||||||
new DatabaseSeeder(dataSource, new ClassPathResource("createAclSchema.sql"));
|
new DatabaseSeeder(dataSource, new ClassPathResource(getSqlClassPathResource()));
|
||||||
// new DatabaseSeeder(dataSource, new
|
// new DatabaseSeeder(dataSource, new
|
||||||
// ClassPathResource("createAclSchemaPostgres.sql"));
|
// ClassPathResource("createAclSchemaPostgres.sql"));
|
||||||
}
|
}
|
||||||
@ -126,9 +146,9 @@ public class JdbcMutableAclServiceTests extends
|
|||||||
public void testLifecycle() {
|
public void testLifecycle() {
|
||||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||||
|
|
||||||
MutableAcl topParent = jdbcMutableAclService.createAcl(topParentOid);
|
MutableAcl topParent = jdbcMutableAclService.createAcl(getTopParentOid());
|
||||||
MutableAcl middleParent = jdbcMutableAclService.createAcl(middleParentOid);
|
MutableAcl middleParent = jdbcMutableAclService.createAcl(getMiddleParentOid());
|
||||||
MutableAcl child = jdbcMutableAclService.createAcl(childOid);
|
MutableAcl child = jdbcMutableAclService.createAcl(getChildOid());
|
||||||
|
|
||||||
// Specify the inheritance hierarchy
|
// Specify the inheritance hierarchy
|
||||||
middleParent.setParent(topParent);
|
middleParent.setParent(topParent);
|
||||||
@ -147,13 +167,13 @@ public class JdbcMutableAclServiceTests extends
|
|||||||
|
|
||||||
// Let's check if we can read them back correctly
|
// Let's check if we can read them back correctly
|
||||||
Map<ObjectIdentity, Acl> map = jdbcMutableAclService.readAclsById(Arrays.asList(
|
Map<ObjectIdentity, Acl> map = jdbcMutableAclService.readAclsById(Arrays.asList(
|
||||||
topParentOid, middleParentOid, childOid));
|
getTopParentOid(), getMiddleParentOid(), getChildOid()));
|
||||||
assertThat(map).hasSize(3);
|
assertThat(map).hasSize(3);
|
||||||
|
|
||||||
// Replace our current objects with their retrieved versions
|
// Replace our current objects with their retrieved versions
|
||||||
topParent = (MutableAcl) map.get(topParentOid);
|
topParent = (MutableAcl) map.get(getTopParentOid());
|
||||||
middleParent = (MutableAcl) map.get(middleParentOid);
|
middleParent = (MutableAcl) map.get(getMiddleParentOid());
|
||||||
child = (MutableAcl) map.get(childOid);
|
child = (MutableAcl) map.get(getChildOid());
|
||||||
|
|
||||||
// Check the retrieved versions has IDs
|
// Check the retrieved versions has IDs
|
||||||
assertThat(topParent.getId()).isNotNull();
|
assertThat(topParent.getId()).isNotNull();
|
||||||
@ -162,8 +182,8 @@ public class JdbcMutableAclServiceTests extends
|
|||||||
|
|
||||||
// Check their parents were correctly persisted
|
// Check their parents were correctly persisted
|
||||||
assertThat(topParent.getParentAcl()).isNull();
|
assertThat(topParent.getParentAcl()).isNull();
|
||||||
assertThat(middleParent.getParentAcl().getObjectIdentity()).isEqualTo(topParentOid);
|
assertThat(middleParent.getParentAcl().getObjectIdentity()).isEqualTo(getTopParentOid());
|
||||||
assertThat(child.getParentAcl().getObjectIdentity()).isEqualTo(middleParentOid);
|
assertThat(child.getParentAcl().getObjectIdentity()).isEqualTo(getMiddleParentOid());
|
||||||
|
|
||||||
// Check their ACEs were correctly persisted
|
// Check their ACEs were correctly persisted
|
||||||
assertThat(topParent.getEntries()).hasSize(2);
|
assertThat(topParent.getEntries()).hasSize(2);
|
||||||
@ -197,7 +217,7 @@ public class JdbcMutableAclServiceTests extends
|
|||||||
// Next change the child so it doesn't inherit permissions from above
|
// Next change the child so it doesn't inherit permissions from above
|
||||||
child.setEntriesInheriting(false);
|
child.setEntriesInheriting(false);
|
||||||
jdbcMutableAclService.updateAcl(child);
|
jdbcMutableAclService.updateAcl(child);
|
||||||
child = (MutableAcl) jdbcMutableAclService.readAclById(childOid);
|
child = (MutableAcl) jdbcMutableAclService.readAclById(getChildOid());
|
||||||
assertThat(child.isEntriesInheriting()).isFalse();
|
assertThat(child.isEntriesInheriting()).isFalse();
|
||||||
|
|
||||||
// Check the child permissions no longer inherit
|
// Check the child permissions no longer inherit
|
||||||
@ -228,7 +248,7 @@ public class JdbcMutableAclServiceTests extends
|
|||||||
|
|
||||||
// Save the changed child
|
// Save the changed child
|
||||||
jdbcMutableAclService.updateAcl(child);
|
jdbcMutableAclService.updateAcl(child);
|
||||||
child = (MutableAcl) jdbcMutableAclService.readAclById(childOid);
|
child = (MutableAcl) jdbcMutableAclService.readAclById(getChildOid());
|
||||||
assertThat(child.getEntries()).hasSize(3);
|
assertThat(child.getEntries()).hasSize(3);
|
||||||
|
|
||||||
// Output permissions
|
// Output permissions
|
||||||
@ -268,38 +288,38 @@ public class JdbcMutableAclServiceTests extends
|
|||||||
public void deleteAclAlsoDeletesChildren() throws Exception {
|
public void deleteAclAlsoDeletesChildren() throws Exception {
|
||||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||||
|
|
||||||
jdbcMutableAclService.createAcl(topParentOid);
|
jdbcMutableAclService.createAcl(getTopParentOid());
|
||||||
MutableAcl middleParent = jdbcMutableAclService.createAcl(middleParentOid);
|
MutableAcl middleParent = jdbcMutableAclService.createAcl(getMiddleParentOid());
|
||||||
MutableAcl child = jdbcMutableAclService.createAcl(childOid);
|
MutableAcl child = jdbcMutableAclService.createAcl(getChildOid());
|
||||||
child.setParent(middleParent);
|
child.setParent(middleParent);
|
||||||
jdbcMutableAclService.updateAcl(middleParent);
|
jdbcMutableAclService.updateAcl(middleParent);
|
||||||
jdbcMutableAclService.updateAcl(child);
|
jdbcMutableAclService.updateAcl(child);
|
||||||
// Check the childOid really is a child of middleParentOid
|
// Check the childOid really is a child of middleParentOid
|
||||||
Acl childAcl = jdbcMutableAclService.readAclById(childOid);
|
Acl childAcl = jdbcMutableAclService.readAclById(getChildOid());
|
||||||
|
|
||||||
assertThat(childAcl.getParentAcl().getObjectIdentity()).isEqualTo(middleParentOid);
|
assertThat(childAcl.getParentAcl().getObjectIdentity()).isEqualTo(getMiddleParentOid());
|
||||||
|
|
||||||
// Delete the mid-parent and test if the child was deleted, as well
|
// Delete the mid-parent and test if the child was deleted, as well
|
||||||
jdbcMutableAclService.deleteAcl(middleParentOid, true);
|
jdbcMutableAclService.deleteAcl(getMiddleParentOid(), true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
jdbcMutableAclService.readAclById(middleParentOid);
|
jdbcMutableAclService.readAclById(getMiddleParentOid());
|
||||||
fail("It should have thrown NotFoundException");
|
fail("It should have thrown NotFoundException");
|
||||||
}
|
}
|
||||||
catch (NotFoundException expected) {
|
catch (NotFoundException expected) {
|
||||||
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
jdbcMutableAclService.readAclById(childOid);
|
jdbcMutableAclService.readAclById(getChildOid());
|
||||||
fail("It should have thrown NotFoundException");
|
fail("It should have thrown NotFoundException");
|
||||||
}
|
}
|
||||||
catch (NotFoundException expected) {
|
catch (NotFoundException expected) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Acl acl = jdbcMutableAclService.readAclById(topParentOid);
|
Acl acl = jdbcMutableAclService.readAclById(getTopParentOid());
|
||||||
assertThat(acl).isNotNull();
|
assertThat(acl).isNotNull();
|
||||||
assertThat(topParentOid).isEqualTo(((MutableAcl) acl).getObjectIdentity());
|
assertThat(getTopParentOid()).isEqualTo(((MutableAcl) acl).getObjectIdentity());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -367,8 +387,8 @@ public class JdbcMutableAclServiceTests extends
|
|||||||
@Transactional
|
@Transactional
|
||||||
public void deleteAclWithChildrenThrowsException() throws Exception {
|
public void deleteAclWithChildrenThrowsException() throws Exception {
|
||||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||||
MutableAcl parent = jdbcMutableAclService.createAcl(topParentOid);
|
MutableAcl parent = jdbcMutableAclService.createAcl(getTopParentOid());
|
||||||
MutableAcl child = jdbcMutableAclService.createAcl(middleParentOid);
|
MutableAcl child = jdbcMutableAclService.createAcl(getMiddleParentOid());
|
||||||
|
|
||||||
// Specify the inheritance hierarchy
|
// Specify the inheritance hierarchy
|
||||||
child.setParent(parent);
|
child.setParent(parent);
|
||||||
@ -378,7 +398,7 @@ public class JdbcMutableAclServiceTests extends
|
|||||||
jdbcMutableAclService.setForeignKeysInDatabase(false); // switch on FK
|
jdbcMutableAclService.setForeignKeysInDatabase(false); // switch on FK
|
||||||
// checking in the
|
// checking in the
|
||||||
// class, not database
|
// class, not database
|
||||||
jdbcMutableAclService.deleteAcl(topParentOid, false);
|
jdbcMutableAclService.deleteAcl(getTopParentOid(), false);
|
||||||
fail("It should have thrown ChildrenExistException");
|
fail("It should have thrown ChildrenExistException");
|
||||||
}
|
}
|
||||||
catch (ChildrenExistException expected) {
|
catch (ChildrenExistException expected) {
|
||||||
@ -393,21 +413,21 @@ public class JdbcMutableAclServiceTests extends
|
|||||||
@Transactional
|
@Transactional
|
||||||
public void deleteAclRemovesRowsFromDatabase() throws Exception {
|
public void deleteAclRemovesRowsFromDatabase() throws Exception {
|
||||||
SecurityContextHolder.getContext().setAuthentication(auth);
|
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||||
MutableAcl child = jdbcMutableAclService.createAcl(childOid);
|
MutableAcl child = jdbcMutableAclService.createAcl(getChildOid());
|
||||||
child.insertAce(0, BasePermission.DELETE, new PrincipalSid(auth), false);
|
child.insertAce(0, BasePermission.DELETE, new PrincipalSid(auth), false);
|
||||||
jdbcMutableAclService.updateAcl(child);
|
jdbcMutableAclService.updateAcl(child);
|
||||||
|
|
||||||
// Remove the child and check all related database rows were removed accordingly
|
// Remove the child and check all related database rows were removed accordingly
|
||||||
jdbcMutableAclService.deleteAcl(childOid, false);
|
jdbcMutableAclService.deleteAcl(getChildOid(), false);
|
||||||
assertThat(
|
assertThat(
|
||||||
jdbcTemplate.queryForList(SELECT_ALL_CLASSES,
|
jdbcTemplate.queryForList(SELECT_ALL_CLASSES,
|
||||||
new Object[] { TARGET_CLASS })).hasSize(1);
|
new Object[] { getTargetClass() })).hasSize(1);
|
||||||
assertThat(jdbcTemplate.queryForList("select * from acl_object_identity")
|
assertThat(jdbcTemplate.queryForList("select * from acl_object_identity")
|
||||||
).isEmpty();
|
).isEmpty();
|
||||||
assertThat(jdbcTemplate.queryForList("select * from acl_entry")).isEmpty();
|
assertThat(jdbcTemplate.queryForList("select * from acl_entry")).isEmpty();
|
||||||
|
|
||||||
// Check the cache
|
// Check the cache
|
||||||
assertThat(aclCache.getFromCache(childOid)).isNull();
|
assertThat(aclCache.getFromCache(getChildOid())).isNull();
|
||||||
assertThat(aclCache.getFromCache(Long.valueOf(102))).isNull();
|
assertThat(aclCache.getFromCache(Long.valueOf(102))).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -573,4 +593,11 @@ public class JdbcMutableAclServiceTests extends
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Authentication getAuth() {
|
||||||
|
return auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected JdbcMutableAclService getJdbcMutableAclService() {
|
||||||
|
return jdbcMutableAclService;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2017 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.security.acls.jdbc;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.security.acls.TargetObjectWithUUID;
|
||||||
|
import org.springframework.security.acls.domain.ObjectIdentityImpl;
|
||||||
|
import org.springframework.security.acls.model.ObjectIdentity;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration tests the ACL system using ACL class id type of UUID and using an in-memory database.
|
||||||
|
* @author Paul Wheeler
|
||||||
|
*/
|
||||||
|
@ContextConfiguration(locations = {"/jdbcMutableAclServiceTestsWithAclClass-context.xml"})
|
||||||
|
public class JdbcMutableAclServiceTestsWithAclClassId extends JdbcMutableAclServiceTests {
|
||||||
|
|
||||||
|
private static final String TARGET_CLASS_WITH_UUID = TargetObjectWithUUID.class.getName();
|
||||||
|
|
||||||
|
private final ObjectIdentity topParentOid = new ObjectIdentityImpl(TARGET_CLASS_WITH_UUID,
|
||||||
|
UUID.randomUUID());
|
||||||
|
private final ObjectIdentity middleParentOid = new ObjectIdentityImpl(TARGET_CLASS_WITH_UUID,
|
||||||
|
UUID.randomUUID());
|
||||||
|
private final ObjectIdentity childOid = new ObjectIdentityImpl(TARGET_CLASS_WITH_UUID,
|
||||||
|
UUID.randomUUID());
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getSqlClassPathResource() {
|
||||||
|
return "createAclSchemaWithAclClassIdType.sql";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ObjectIdentity getTopParentOid() {
|
||||||
|
return topParentOid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ObjectIdentity getMiddleParentOid() {
|
||||||
|
return middleParentOid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ObjectIdentity getChildOid() {
|
||||||
|
return childOid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getTargetClass() {
|
||||||
|
return TARGET_CLASS_WITH_UUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Transactional
|
||||||
|
public void identityWithUuidIdIsSupportedByCreateAcl() throws Exception {
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(getAuth());
|
||||||
|
|
||||||
|
UUID id = UUID.randomUUID();
|
||||||
|
ObjectIdentity oid = new ObjectIdentityImpl(TARGET_CLASS_WITH_UUID, id);
|
||||||
|
getJdbcMutableAclService().createAcl(oid);
|
||||||
|
|
||||||
|
assertThat(getJdbcMutableAclService().readAclById(new ObjectIdentityImpl(
|
||||||
|
TARGET_CLASS_WITH_UUID, id))).isNotNull();
|
||||||
|
}
|
||||||
|
}
|
@ -17,7 +17,10 @@
|
|||||||
<constructor-arg>
|
<constructor-arg>
|
||||||
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
|
<bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
|
||||||
<property name="cacheManager">
|
<property name="cacheManager">
|
||||||
<bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
|
<bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
|
||||||
|
<!-- This context is used in two tests so accept existing cache manager as the context will be reused -->
|
||||||
|
<property name="acceptExisting" value="true"/>
|
||||||
|
</bean>
|
||||||
</property>
|
</property>
|
||||||
<property name="cacheName" value="aclCache"/>
|
<property name="cacheName" value="aclCache"/>
|
||||||
</bean>
|
</bean>
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||||
|
|
||||||
|
<import resource="jdbcMutableAclServiceTests-context.xml"/>
|
||||||
|
|
||||||
|
<bean id="aclClassIdUtils" class="org.springframework.security.acls.jdbc.AclClassIdUtils">
|
||||||
|
<property name="conversionService">
|
||||||
|
<bean class="org.springframework.core.convert.support.DefaultConversionService"/>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
<!-- Overridden bean definitions -->
|
||||||
|
|
||||||
|
<bean id="aclService" class="org.springframework.security.acls.jdbc.JdbcMutableAclService">
|
||||||
|
<constructor-arg ref="dataSource"/>
|
||||||
|
<constructor-arg ref="lookupStrategy"/>
|
||||||
|
<constructor-arg ref="aclCache"/>
|
||||||
|
<property name="aclClassIdSupported" value="true"/>
|
||||||
|
<property name="aclClassIdUtils" ref="aclClassIdUtils"/>
|
||||||
|
</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>
|
||||||
|
<bean class="org.springframework.security.acls.domain.ConsoleAuditLogger"/>
|
||||||
|
</constructor-arg>
|
||||||
|
<property name="aclClassIdSupported" value="true"/>
|
||||||
|
<property name="aclClassIdUtils" ref="aclClassIdUtils"/>
|
||||||
|
</bean>
|
||||||
|
</beans>
|
@ -7313,7 +7313,7 @@ create table acl_class(
|
|||||||
create table acl_object_identity(
|
create table acl_object_identity(
|
||||||
id bigint generated by default as identity(start with 100) not null primary key,
|
id bigint generated by default as identity(start with 100) not null primary key,
|
||||||
object_id_class bigint not null,
|
object_id_class bigint not null,
|
||||||
object_id_identity bigint not null,
|
object_id_identity varchar_ignorecase(36) not null,
|
||||||
parent_object bigint,
|
parent_object bigint,
|
||||||
owner_sid bigint,
|
owner_sid bigint,
|
||||||
entries_inheriting boolean not null,
|
entries_inheriting boolean not null,
|
||||||
@ -7357,7 +7357,7 @@ create table acl_class(
|
|||||||
create table acl_object_identity(
|
create table acl_object_identity(
|
||||||
id bigserial primary key,
|
id bigserial primary key,
|
||||||
object_id_class bigint not null,
|
object_id_class bigint not null,
|
||||||
object_id_identity bigint not null,
|
object_id_identity varchar(36) not null,
|
||||||
parent_object bigint,
|
parent_object bigint,
|
||||||
owner_sid bigint,
|
owner_sid bigint,
|
||||||
entries_inheriting boolean not null,
|
entries_inheriting boolean not null,
|
||||||
@ -7406,7 +7406,7 @@ CREATE TABLE acl_class (
|
|||||||
CREATE TABLE acl_object_identity (
|
CREATE TABLE acl_object_identity (
|
||||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
object_id_class BIGINT UNSIGNED NOT NULL,
|
object_id_class BIGINT UNSIGNED NOT NULL,
|
||||||
object_id_identity BIGINT NOT NULL,
|
object_id_identity VARCHAR(36) NOT NULL,
|
||||||
parent_object BIGINT UNSIGNED,
|
parent_object BIGINT UNSIGNED,
|
||||||
owner_sid BIGINT UNSIGNED,
|
owner_sid BIGINT UNSIGNED,
|
||||||
entries_inheriting BOOLEAN NOT NULL,
|
entries_inheriting BOOLEAN NOT NULL,
|
||||||
@ -7450,7 +7450,7 @@ CREATE TABLE acl_class (
|
|||||||
CREATE TABLE acl_object_identity (
|
CREATE TABLE acl_object_identity (
|
||||||
id BIGINT NOT NULL IDENTITY PRIMARY KEY,
|
id BIGINT NOT NULL IDENTITY PRIMARY KEY,
|
||||||
object_id_class BIGINT NOT NULL,
|
object_id_class BIGINT NOT NULL,
|
||||||
object_id_identity BIGINT NOT NULL,
|
object_id_identity VARCHAR(36) NOT NULL,
|
||||||
parent_object BIGINT,
|
parent_object BIGINT,
|
||||||
owner_sid BIGINT,
|
owner_sid BIGINT,
|
||||||
entries_inheriting BIT NOT NULL,
|
entries_inheriting BIT NOT NULL,
|
||||||
@ -7508,7 +7508,7 @@ END;
|
|||||||
CREATE TABLE acl_object_identity (
|
CREATE TABLE acl_object_identity (
|
||||||
id NUMBER(38) NOT NULL PRIMARY KEY,
|
id NUMBER(38) NOT NULL PRIMARY KEY,
|
||||||
object_id_class NUMBER(38) NOT NULL,
|
object_id_class NUMBER(38) NOT NULL,
|
||||||
object_id_identity NUMBER(38) NOT NULL,
|
object_id_identity NVARCHAR2(36) NOT NULL,
|
||||||
parent_object NUMBER(38),
|
parent_object NUMBER(38),
|
||||||
owner_sid NUMBER(38),
|
owner_sid NUMBER(38),
|
||||||
entries_inheriting NUMBER(1) NOT NULL CHECK (entries_inheriting in (0, 1)),
|
entries_inheriting NUMBER(1) NOT NULL CHECK (entries_inheriting in (0, 1)),
|
||||||
|
@ -95,11 +95,12 @@ public class DataSourcePopulator implements InitializingBean {
|
|||||||
template.execute("CREATE TABLE ACL_CLASS("
|
template.execute("CREATE TABLE ACL_CLASS("
|
||||||
+ "ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,"
|
+ "ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,"
|
||||||
+ "CLASS VARCHAR_IGNORECASE(100) NOT NULL,"
|
+ "CLASS VARCHAR_IGNORECASE(100) NOT NULL,"
|
||||||
|
+ "CLASS_ID_TYPE VARCHAR_IGNORECASE(100),"
|
||||||
+ "CONSTRAINT UNIQUE_UK_2 UNIQUE(CLASS));");
|
+ "CONSTRAINT UNIQUE_UK_2 UNIQUE(CLASS));");
|
||||||
template.execute("CREATE TABLE ACL_OBJECT_IDENTITY("
|
template.execute("CREATE TABLE ACL_OBJECT_IDENTITY("
|
||||||
+ "ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,"
|
+ "ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,"
|
||||||
+ "OBJECT_ID_CLASS BIGINT NOT NULL,"
|
+ "OBJECT_ID_CLASS BIGINT NOT NULL,"
|
||||||
+ "OBJECT_ID_IDENTITY BIGINT NOT NULL,"
|
+ "OBJECT_ID_IDENTITY VARCHAR_IGNORECASE(36) NOT NULL,"
|
||||||
+ "PARENT_OBJECT BIGINT,"
|
+ "PARENT_OBJECT BIGINT,"
|
||||||
+ "OWNER_SID BIGINT,"
|
+ "OWNER_SID BIGINT,"
|
||||||
+ "ENTRIES_INHERITING BOOLEAN NOT NULL,"
|
+ "ENTRIES_INHERITING BOOLEAN NOT NULL,"
|
||||||
|
@ -48,8 +48,8 @@ public class DataSourcePopulator implements InitializingBean {
|
|||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws Exception {
|
||||||
// ACL tables
|
// ACL tables
|
||||||
template.execute("CREATE TABLE ACL_SID(ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,PRINCIPAL BOOLEAN NOT NULL,SID VARCHAR_IGNORECASE(100) NOT NULL,CONSTRAINT UNIQUE_UK_1 UNIQUE(SID,PRINCIPAL));");
|
template.execute("CREATE TABLE ACL_SID(ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,PRINCIPAL BOOLEAN NOT NULL,SID VARCHAR_IGNORECASE(100) NOT NULL,CONSTRAINT UNIQUE_UK_1 UNIQUE(SID,PRINCIPAL));");
|
||||||
template.execute("CREATE TABLE ACL_CLASS(ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,CLASS VARCHAR_IGNORECASE(100) NOT NULL,CONSTRAINT UNIQUE_UK_2 UNIQUE(CLASS));");
|
template.execute("CREATE TABLE ACL_CLASS(ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,CLASS VARCHAR_IGNORECASE(100) NOT NULL,CLASS_ID_TYPE VARCHAR_IGNORECASE(100),CONSTRAINT UNIQUE_UK_2 UNIQUE(CLASS));");
|
||||||
template.execute("CREATE TABLE ACL_OBJECT_IDENTITY(ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL 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));");
|
template.execute("CREATE TABLE ACL_OBJECT_IDENTITY(ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL PRIMARY KEY,OBJECT_ID_CLASS BIGINT NOT NULL,OBJECT_ID_IDENTITY VARCHAR_IGNORECASE(36) 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));");
|
||||||
template.execute("CREATE TABLE ACL_ENTRY(ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL 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));");
|
template.execute("CREATE TABLE ACL_ENTRY(ID BIGINT GENERATED BY DEFAULT AS IDENTITY(START WITH 100) NOT NULL 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));");
|
||||||
|
|
||||||
// Normal authentication tables
|
// Normal authentication tables
|
||||||
|
Loading…
x
Reference in New Issue
Block a user