001    /**
002     * 
003     */
004    package org.springframework.richclient.security.support;
005    
006    import java.util.ArrayList;
007    
008    import junit.framework.TestCase;
009    
010    import org.springframework.security.AccessDecisionManager;
011    import org.springframework.security.AccessDeniedException;
012    import org.springframework.security.Authentication;
013    import org.springframework.security.ConfigAttribute;
014    import org.springframework.security.ConfigAttributeDefinition;
015    import org.springframework.security.providers.TestingAuthenticationToken;
016    
017    /**
018     * @author Larry Streepy
019     * 
020     */
021    public class SecurityControllerTests extends TestCase {
022    
023        private TestAbstractSecurityController controller;
024        private TestAccessDecisionManager accessDecisionManager;
025    
026        /*
027         * @see TestCase#setUp()
028         */
029        protected void setUp() throws Exception {
030            super.setUp();
031            controller = new TestAbstractSecurityController();
032            accessDecisionManager = new TestAccessDecisionManager();
033            controller.setAccessDecisionManager(accessDecisionManager);
034        }
035    
036        /**
037         * Test that setting the authentication token updates all controlled objects.
038         */
039        public void testSetAuthenticationToken() {
040    
041            // Validate that the controller updates the controlled objects whenever the
042            // Authentication token is updated
043            TestAuthorizable a1 = new TestAuthorizable( true );
044            TestAuthorizable a2 = new TestAuthorizable( true );
045            controller.addControlledObject( a1 );
046            controller.addControlledObject( a2 );
047            assertFalse( "Object should not be authorized", a1.isAuthorized() );
048            assertFalse( "Object should not be authorized", a2.isAuthorized() );
049    
050            a1.resetAuthCount();
051            a2.resetAuthCount();
052    
053            // Set the decision manager to authorize
054            accessDecisionManager.setDecisionValue( true );
055    
056            // Now install a token, a should be updated
057            controller.setAuthenticationToken( new TestingAuthenticationToken( "USER2", "FOO") );
058            assertTrue( "Object should be authorized", a1.isAuthorized() );
059            assertEquals( "Object should be updated", a1.getAuthCount(), 1 );
060            assertTrue( "Object should be authorized", a2.isAuthorized() );
061            assertEquals( "Object should be updated", a2.getAuthCount(), 1 );
062    
063            controller.setAuthenticationToken( null );
064            assertFalse( "Object should not be authorized", a1.isAuthorized() );
065            assertEquals( "Object should be updated", a1.getAuthCount(), 2 );
066            assertFalse( "Object should not be authorized", a2.isAuthorized() );
067            assertEquals( "Object should be updated", a2.getAuthCount(), 2 );
068    
069            // Set the decision manager to NOT authorize
070            accessDecisionManager.setDecisionValue( false );
071    
072            // Now install a token, a should be updated
073            controller.setAuthenticationToken( new TestingAuthenticationToken( "USER2", "FOO") );
074            assertFalse( "Object should not be authorized", a1.isAuthorized() );
075            assertEquals( "Object should be updated", a1.getAuthCount(), 3 );
076            assertFalse( "Object should not be authorized", a2.isAuthorized() );
077            assertEquals( "Object should be updated", a2.getAuthCount(), 3 );
078        }
079    
080        public void testSetControlledObjects() {
081    
082            TestAuthorizable a1 = new TestAuthorizable( true );
083            TestAuthorizable a2 = new TestAuthorizable( true );
084            ArrayList goodList = new ArrayList();
085            goodList.add( a1 );
086            goodList.add( a2 );
087    
088            ArrayList badList = new ArrayList();
089            badList.add( new Object() );
090    
091            try {
092                controller.setControlledObjects( badList );
093                fail( "Should reject objects that aren't Authorizable" );
094            } catch( IllegalArgumentException e ) {
095                // expected
096            }
097    
098            controller.setControlledObjects( goodList );
099            assertFalse( "Object should not be authorized", a1.isAuthorized() );
100            assertTrue( "Object should be updated", a1.getAuthCount() == 1 );
101            assertFalse( "Object should not be authorized", a2.isAuthorized() );
102            assertTrue( "Object should be updated", a2.getAuthCount() == 1 );
103        }
104    
105        /**
106         * Test that added objects are initially configured.
107         */
108        public void testAddControlledObject() {
109    
110            // Install an authentication token
111            controller.setAuthenticationToken( new TestingAuthenticationToken( "USER2", "FOO") );
112    
113            // Set the decision manager to authorize
114            accessDecisionManager.setDecisionValue( true );
115    
116            TestAuthorizable a1 = new TestAuthorizable( false );
117            controller.addControlledObject( a1 );
118            assertTrue( "Object should be authorized", a1.isAuthorized() );
119            assertTrue( "Object should be updated", a1.getAuthCount() == 1 );
120    
121            // Set the decision manager to NOT authorize
122            accessDecisionManager.setDecisionValue( false );
123    
124            TestAuthorizable a2 = new TestAuthorizable( true );
125            controller.addControlledObject( a2 );
126            assertFalse( "Object should not be authorized", a2.isAuthorized() );
127            assertTrue( "Object should be updated", a2.getAuthCount() == 1 );
128        }
129    
130        /**
131         * Test that once removed an object is no longer updated.
132         */
133        public void testRemoveControlledObject() {
134            TestAuthorizable a = new TestAuthorizable( true );
135            controller.addControlledObject( a );
136            assertFalse( "Object should not be authorized", a.isAuthorized() );
137            assertTrue( "Object should be updated", a.getAuthCount() == 1 );
138    
139            controller.removeControlledObject( a );
140            a.resetAuthCount();
141    
142            // Set the decision manager to authorize
143            accessDecisionManager.setDecisionValue( true );
144            controller.setAuthenticationToken( new TestingAuthenticationToken( "USER2", "FOO" ) );
145    
146            assertFalse( "Object should not be authorized", a.isAuthorized() );
147            assertTrue( "Object should not be updated", a.getAuthCount() == 0 );
148        }
149    
150        /**
151         * Concrete implementation under test.
152         */
153        public class TestAbstractSecurityController extends AbstractSecurityController {
154    
155            public TestAbstractSecurityController() {
156            }
157    
158            protected Object getSecuredObject() {
159                return null;
160            }
161    
162            protected ConfigAttributeDefinition getConfigAttributeDefinition(Object securedObject) {
163                return null;
164            }
165        }
166    
167        /**
168         * Controllable AccessDecisionManager
169         */
170        public class TestAccessDecisionManager implements AccessDecisionManager {
171    
172            private boolean decisionValue;
173    
174            public void setDecisionValue(boolean decisionValue) {
175                this.decisionValue = decisionValue;
176            }
177    
178            public void decide(Authentication authentication, Object object, ConfigAttributeDefinition config)
179                    throws AccessDeniedException {
180                if( !decisionValue) {
181                    throw new AccessDeniedException( "access denied" );
182                }
183            }
184    
185            public boolean supports(ConfigAttribute attribute) {
186                return false;
187            }
188    
189            public boolean supports(Class clazz) {
190                return false;
191            }
192        }
193    }