2 changed files with 439 additions and 0 deletions
@ -0,0 +1,297 @@
@@ -0,0 +1,297 @@
|
||||
package org.springframework.security.acls.domain; |
||||
|
||||
import junit.framework.Assert; |
||||
|
||||
import org.junit.After; |
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
import org.springframework.security.AccessDeniedException; |
||||
import org.springframework.security.Authentication; |
||||
import org.springframework.security.GrantedAuthority; |
||||
import org.springframework.security.GrantedAuthorityImpl; |
||||
import org.springframework.security.acls.Acl; |
||||
import org.springframework.security.acls.MutableAcl; |
||||
import org.springframework.security.acls.NotFoundException; |
||||
import org.springframework.security.acls.objectidentity.ObjectIdentity; |
||||
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl; |
||||
import org.springframework.security.acls.sid.PrincipalSid; |
||||
import org.springframework.security.context.SecurityContextHolder; |
||||
import org.springframework.security.providers.TestingAuthenticationToken; |
||||
|
||||
/** |
||||
* Test class for {@link AclAuthorizationStrategyImpl} and {@link AclImpl} |
||||
* security checks. |
||||
* |
||||
* @author Andrei Stefan |
||||
*/ |
||||
public class AclImplementationSecurityCheckTests { |
||||
@Before |
||||
@After |
||||
public void clearContext() { |
||||
SecurityContextHolder.clearContext(); |
||||
} |
||||
|
||||
@Test |
||||
public void securityCheckNoACEs() { |
||||
Authentication auth = new TestingAuthenticationToken("user", "password", new GrantedAuthority[] { |
||||
new GrantedAuthorityImpl("ROLE_GENERAL"), new GrantedAuthorityImpl("ROLE_AUDITING"), |
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP") }); |
||||
auth.setAuthenticated(true); |
||||
SecurityContextHolder.getContext().setAuthentication(auth); |
||||
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100)); |
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] { |
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"), |
||||
new GrantedAuthorityImpl("ROLE_GENERAL") }); |
||||
|
||||
Acl acl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger()); |
||||
try { |
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_GENERAL); |
||||
Assert.assertTrue(true); |
||||
} |
||||
catch (AccessDeniedException notExpected) { |
||||
Assert.fail("It shouldn't have thrown AccessDeniedException"); |
||||
} |
||||
try { |
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_AUDITING); |
||||
Assert.assertTrue(true); |
||||
} |
||||
catch (AccessDeniedException notExpected) { |
||||
Assert.fail("It shouldn't have thrown AccessDeniedException"); |
||||
} |
||||
try { |
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_OWNERSHIP); |
||||
Assert.assertTrue(true); |
||||
} |
||||
catch (AccessDeniedException notExpected) { |
||||
Assert.fail("It shouldn't have thrown AccessDeniedException"); |
||||
} |
||||
|
||||
// Create another authorization strategy
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy2 = new AclAuthorizationStrategyImpl(new GrantedAuthority[] { |
||||
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO"), |
||||
new GrantedAuthorityImpl("ROLE_THREE") }); |
||||
Acl acl2 = new AclImpl(identity, new Long(1), aclAuthorizationStrategy2, new ConsoleAuditLogger()); |
||||
// Check access in case the principal has no authorization rights
|
||||
try { |
||||
aclAuthorizationStrategy2.securityCheck(acl2, AclAuthorizationStrategy.CHANGE_GENERAL); |
||||
Assert.fail("It should have thrown NotFoundException"); |
||||
} |
||||
catch (NotFoundException expected) { |
||||
Assert.assertTrue(true); |
||||
} |
||||
try { |
||||
aclAuthorizationStrategy2.securityCheck(acl2, AclAuthorizationStrategy.CHANGE_AUDITING); |
||||
Assert.fail("It should have thrown NotFoundException"); |
||||
} |
||||
catch (NotFoundException expected) { |
||||
Assert.assertTrue(true); |
||||
} |
||||
try { |
||||
aclAuthorizationStrategy2.securityCheck(acl2, AclAuthorizationStrategy.CHANGE_OWNERSHIP); |
||||
Assert.fail("It should have thrown NotFoundException"); |
||||
} |
||||
catch (NotFoundException expected) { |
||||
Assert.assertTrue(true); |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void securityCheckWithMultipleACEs() { |
||||
// Create a simple authentication with ROLE_GENERAL
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password", |
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_GENERAL") }); |
||||
auth.setAuthenticated(true); |
||||
SecurityContextHolder.getContext().setAuthentication(auth); |
||||
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100)); |
||||
// Authorization strategy will require a different role for each access
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] { |
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"), |
||||
new GrantedAuthorityImpl("ROLE_GENERAL") }); |
||||
|
||||
// Let's give the principal the ADMINISTRATION permission, without
|
||||
// granting access
|
||||
MutableAcl aclFirstDeny = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger()); |
||||
aclFirstDeny.insertAce(null, BasePermission.ADMINISTRATION, new PrincipalSid(auth), false); |
||||
|
||||
// The CHANGE_GENERAL test should pass as the principal has ROLE_GENERAL
|
||||
try { |
||||
aclAuthorizationStrategy.securityCheck(aclFirstDeny, AclAuthorizationStrategy.CHANGE_GENERAL); |
||||
Assert.assertTrue(true); |
||||
} |
||||
catch (AccessDeniedException notExpected) { |
||||
Assert.fail("It shouldn't have thrown AccessDeniedException"); |
||||
} |
||||
// The CHANGE_AUDITING and CHANGE_OWNERSHIP should fail since the
|
||||
// principal doesn't have these authorities,
|
||||
// nor granting access
|
||||
try { |
||||
aclAuthorizationStrategy.securityCheck(aclFirstDeny, AclAuthorizationStrategy.CHANGE_AUDITING); |
||||
Assert.fail("It should have thrown AccessDeniedException"); |
||||
} |
||||
catch (AccessDeniedException expected) { |
||||
Assert.assertTrue(true); |
||||
} |
||||
try { |
||||
aclAuthorizationStrategy.securityCheck(aclFirstDeny, AclAuthorizationStrategy.CHANGE_OWNERSHIP); |
||||
Assert.fail("It should have thrown AccessDeniedException"); |
||||
} |
||||
catch (AccessDeniedException expected) { |
||||
Assert.assertTrue(true); |
||||
} |
||||
|
||||
// Add granting access to this principal
|
||||
aclFirstDeny.insertAce(null, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true); |
||||
// and try again for CHANGE_AUDITING - the first ACE's granting flag
|
||||
// (false) will deny this access
|
||||
try { |
||||
aclAuthorizationStrategy.securityCheck(aclFirstDeny, AclAuthorizationStrategy.CHANGE_AUDITING); |
||||
Assert.fail("It should have thrown AccessDeniedException"); |
||||
} |
||||
catch (AccessDeniedException expected) { |
||||
Assert.assertTrue(true); |
||||
} |
||||
|
||||
// Create another ACL and give the principal the ADMINISTRATION
|
||||
// permission, with granting access
|
||||
MutableAcl aclFirstAllow = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, |
||||
new ConsoleAuditLogger()); |
||||
aclFirstAllow.insertAce(null, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true); |
||||
|
||||
// The CHANGE_AUDITING test should pass as there is one ACE with
|
||||
// granting access
|
||||
try { |
||||
aclAuthorizationStrategy.securityCheck(aclFirstAllow, AclAuthorizationStrategy.CHANGE_AUDITING); |
||||
Assert.assertTrue(true); |
||||
} |
||||
catch (AccessDeniedException notExpected) { |
||||
Assert.fail("It shouldn't have thrown AccessDeniedException"); |
||||
} |
||||
|
||||
// Add a deny ACE and test again for CHANGE_AUDITING
|
||||
aclFirstAllow.insertAce(null, BasePermission.ADMINISTRATION, new PrincipalSid(auth), false); |
||||
try { |
||||
aclAuthorizationStrategy.securityCheck(aclFirstAllow, AclAuthorizationStrategy.CHANGE_AUDITING); |
||||
Assert.assertTrue(true); |
||||
} |
||||
catch (AccessDeniedException notExpected) { |
||||
Assert.fail("It shouldn't have thrown AccessDeniedException"); |
||||
} |
||||
|
||||
// Create an ACL with no ACE
|
||||
MutableAcl aclNoACE = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger()); |
||||
try { |
||||
aclAuthorizationStrategy.securityCheck(aclNoACE, AclAuthorizationStrategy.CHANGE_AUDITING); |
||||
Assert.fail("It should have thrown NotFoundException"); |
||||
} |
||||
catch (NotFoundException expected) { |
||||
Assert.assertTrue(true); |
||||
} |
||||
// and still grant access for CHANGE_GENERAL
|
||||
try { |
||||
aclAuthorizationStrategy.securityCheck(aclNoACE, AclAuthorizationStrategy.CHANGE_GENERAL); |
||||
Assert.assertTrue(true); |
||||
} |
||||
catch (NotFoundException expected) { |
||||
Assert.fail("It shouldn't have thrown NotFoundException"); |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void securityCheckWithInheritableACEs() { |
||||
// Create a simple authentication with ROLE_GENERAL
|
||||
Authentication auth = new TestingAuthenticationToken("user", "password", |
||||
new GrantedAuthority[] { new GrantedAuthorityImpl("ROLE_GENERAL") }); |
||||
auth.setAuthenticated(true); |
||||
SecurityContextHolder.getContext().setAuthentication(auth); |
||||
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100)); |
||||
// Authorization strategy will require a different role for each access
|
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] { |
||||
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO"), |
||||
new GrantedAuthorityImpl("ROLE_GENERAL") }); |
||||
|
||||
// Let's give the principal an ADMINISTRATION permission, with granting
|
||||
// access
|
||||
MutableAcl parentAcl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger()); |
||||
parentAcl.insertAce(null, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true); |
||||
MutableAcl childAcl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger()); |
||||
|
||||
// Check against the 'child' acl, which doesn't offer any authorization
|
||||
// rights on CHANGE_OWNERSHIP
|
||||
try { |
||||
aclAuthorizationStrategy.securityCheck(childAcl, AclAuthorizationStrategy.CHANGE_OWNERSHIP); |
||||
Assert.fail("It should have thrown NotFoundException"); |
||||
} |
||||
catch (NotFoundException expected) { |
||||
Assert.assertTrue(true); |
||||
} |
||||
|
||||
// Link the child with its parent and test again against the
|
||||
// CHANGE_OWNERSHIP right
|
||||
childAcl.setParent(parentAcl); |
||||
childAcl.setEntriesInheriting(true); |
||||
try { |
||||
aclAuthorizationStrategy.securityCheck(childAcl, AclAuthorizationStrategy.CHANGE_OWNERSHIP); |
||||
Assert.assertTrue(true); |
||||
} |
||||
catch (NotFoundException expected) { |
||||
Assert.fail("It shouldn't have thrown NotFoundException"); |
||||
} |
||||
|
||||
// Create a root parent and link it to the middle parent
|
||||
MutableAcl rootParentAcl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, |
||||
new ConsoleAuditLogger()); |
||||
parentAcl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger()); |
||||
rootParentAcl.insertAce(null, BasePermission.ADMINISTRATION, new PrincipalSid(auth), true); |
||||
parentAcl.setEntriesInheriting(true); |
||||
parentAcl.setParent(rootParentAcl); |
||||
childAcl.setParent(parentAcl); |
||||
try { |
||||
aclAuthorizationStrategy.securityCheck(childAcl, AclAuthorizationStrategy.CHANGE_OWNERSHIP); |
||||
Assert.assertTrue(true); |
||||
} |
||||
catch (NotFoundException expected) { |
||||
Assert.fail("It shouldn't have thrown NotFoundException"); |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void securityCheckPrincipalOwner() { |
||||
Authentication auth = new TestingAuthenticationToken("user", "password", new GrantedAuthority[] { |
||||
new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_ONE"), |
||||
new GrantedAuthorityImpl("ROLE_ONE") }); |
||||
auth.setAuthenticated(true); |
||||
SecurityContextHolder.getContext().setAuthentication(auth); |
||||
|
||||
ObjectIdentity identity = new ObjectIdentityImpl("org.springframework.security.TargetObject", new Long(100)); |
||||
AclAuthorizationStrategy aclAuthorizationStrategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] { |
||||
new GrantedAuthorityImpl("ROLE_OWNERSHIP"), new GrantedAuthorityImpl("ROLE_AUDITING"), |
||||
new GrantedAuthorityImpl("ROLE_GENERAL") }); |
||||
|
||||
Acl acl = new AclImpl(identity, new Long(1), aclAuthorizationStrategy, new ConsoleAuditLogger(), null, null, |
||||
false, new PrincipalSid(auth)); |
||||
try { |
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_GENERAL); |
||||
Assert.assertTrue(true); |
||||
} |
||||
catch (AccessDeniedException notExpected) { |
||||
Assert.fail("It shouldn't have thrown AccessDeniedException"); |
||||
} |
||||
try { |
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_AUDITING); |
||||
Assert.fail("It shouldn't have thrown AccessDeniedException"); |
||||
} |
||||
catch (NotFoundException expected) { |
||||
Assert.assertTrue(true); |
||||
} |
||||
try { |
||||
aclAuthorizationStrategy.securityCheck(acl, AclAuthorizationStrategy.CHANGE_OWNERSHIP); |
||||
Assert.assertTrue(true); |
||||
} |
||||
catch (AccessDeniedException notExpected) { |
||||
Assert.fail("It shouldn't have thrown AccessDeniedException"); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,142 @@
@@ -0,0 +1,142 @@
|
||||
package org.springframework.security.acls.domain; |
||||
|
||||
import java.io.ByteArrayOutputStream; |
||||
import java.io.PrintStream; |
||||
import java.io.Serializable; |
||||
|
||||
import junit.framework.Assert; |
||||
|
||||
import org.junit.After; |
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
import org.springframework.security.acls.AccessControlEntry; |
||||
import org.springframework.security.acls.Acl; |
||||
import org.springframework.security.acls.AuditableAccessControlEntry; |
||||
import org.springframework.security.acls.Permission; |
||||
import org.springframework.security.acls.sid.Sid; |
||||
|
||||
/** |
||||
* Test class for {@link ConsoleAuditLogger}. |
||||
* |
||||
* @author Andrei Stefan |
||||
*/ |
||||
public class AuditLoggerTests { |
||||
private PrintStream console; |
||||
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream(); |
||||
|
||||
@Before |
||||
public void onSetUp() { |
||||
console = System.out; |
||||
System.setOut(new PrintStream(bytes)); |
||||
} |
||||
|
||||
@After |
||||
public void onTearDown() { |
||||
System.setOut(console); |
||||
} |
||||
|
||||
@Test |
||||
public void loggingTests() { |
||||
ConsoleAuditLogger logger = new ConsoleAuditLogger(); |
||||
MockAccessControlEntryImpl auditableAccessControlEntry = new MockAccessControlEntryImpl(); |
||||
|
||||
logger.logIfNeeded(true, auditableAccessControlEntry); |
||||
Assert.assertTrue(bytes.size() == 0); |
||||
|
||||
bytes.reset(); |
||||
logger.logIfNeeded(false, auditableAccessControlEntry); |
||||
Assert.assertTrue(bytes.size() == 0); |
||||
|
||||
auditableAccessControlEntry.setAuditSuccess(true); |
||||
bytes.reset(); |
||||
|
||||
logger.logIfNeeded(true, auditableAccessControlEntry); |
||||
Assert.assertTrue(bytes.toString().length() > 0); |
||||
Assert.assertTrue(bytes.toString().startsWith("GRANTED due to ACE")); |
||||
|
||||
auditableAccessControlEntry.setAuditFailure(true); |
||||
bytes.reset(); |
||||
|
||||
logger.logIfNeeded(false, auditableAccessControlEntry); |
||||
Assert.assertTrue(bytes.toString().length() > 0); |
||||
Assert.assertTrue(bytes.toString().startsWith("DENIED due to ACE")); |
||||
|
||||
MockAccessControlEntry accessControlEntry = new MockAccessControlEntry(); |
||||
bytes.reset(); |
||||
logger.logIfNeeded(true, accessControlEntry); |
||||
Assert.assertTrue(bytes.size() == 0); |
||||
} |
||||
|
||||
/** |
||||
* Mock {@link AuditableAccessControlEntry}. |
||||
*/ |
||||
private class MockAccessControlEntryImpl implements AuditableAccessControlEntry { |
||||
private boolean auditFailure = false; |
||||
|
||||
private boolean auditSuccess = false; |
||||
|
||||
public boolean isAuditFailure() { |
||||
return auditFailure; |
||||
} |
||||
|
||||
public boolean isAuditSuccess() { |
||||
return auditSuccess; |
||||
} |
||||
|
||||
public Acl getAcl() { |
||||
return null; |
||||
} |
||||
|
||||
public Serializable getId() { |
||||
return null; |
||||
} |
||||
|
||||
public Permission getPermission() { |
||||
return null; |
||||
} |
||||
|
||||
public Sid getSid() { |
||||
return null; |
||||
} |
||||
|
||||
public boolean isGranting() { |
||||
return false; |
||||
} |
||||
|
||||
public void setAuditFailure(boolean auditFailure) { |
||||
this.auditFailure = auditFailure; |
||||
} |
||||
|
||||
public void setAuditSuccess(boolean auditSuccess) { |
||||
this.auditSuccess = auditSuccess; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Mock {@link AccessControlEntry}. |
||||
*/ |
||||
private class MockAccessControlEntry implements AccessControlEntry { |
||||
|
||||
public Acl getAcl() { |
||||
return null; |
||||
} |
||||
|
||||
public Serializable getId() { |
||||
return null; |
||||
} |
||||
|
||||
public Permission getPermission() { |
||||
return null; |
||||
} |
||||
|
||||
public Sid getSid() { |
||||
return null; |
||||
} |
||||
|
||||
public boolean isGranting() { |
||||
return false; |
||||
} |
||||
|
||||
} |
||||
} |
||||
Loading…
Reference in new issue