1   /**
2    * 
3    */
4   package org.springframework.richclient.security.support;
5   
6   import java.util.ArrayList;
7   
8   import junit.framework.TestCase;
9   
10  import org.springframework.security.AccessDecisionManager;
11  import org.springframework.security.AccessDeniedException;
12  import org.springframework.security.Authentication;
13  import org.springframework.security.ConfigAttribute;
14  import org.springframework.security.ConfigAttributeDefinition;
15  import org.springframework.security.providers.TestingAuthenticationToken;
16  
17  /**
18   * @author Larry Streepy
19   * 
20   */
21  public class SecurityControllerTests extends TestCase {
22  
23      private TestAbstractSecurityController controller;
24      private TestAccessDecisionManager accessDecisionManager;
25  
26      /*
27       * @see TestCase#setUp()
28       */
29      protected void setUp() throws Exception {
30          super.setUp();
31          controller = new TestAbstractSecurityController();
32          accessDecisionManager = new TestAccessDecisionManager();
33          controller.setAccessDecisionManager(accessDecisionManager);
34      }
35  
36      /**
37       * Test that setting the authentication token updates all controlled objects.
38       */
39      public void testSetAuthenticationToken() {
40  
41          // Validate that the controller updates the controlled objects whenever the
42          // Authentication token is updated
43          TestAuthorizable a1 = new TestAuthorizable( true );
44          TestAuthorizable a2 = new TestAuthorizable( true );
45          controller.addControlledObject( a1 );
46          controller.addControlledObject( a2 );
47          assertFalse( "Object should not be authorized", a1.isAuthorized() );
48          assertFalse( "Object should not be authorized", a2.isAuthorized() );
49  
50          a1.resetAuthCount();
51          a2.resetAuthCount();
52  
53          // Set the decision manager to authorize
54          accessDecisionManager.setDecisionValue( true );
55  
56          // Now install a token, a should be updated
57          controller.setAuthenticationToken( new TestingAuthenticationToken( "USER2", "FOO") );
58          assertTrue( "Object should be authorized", a1.isAuthorized() );
59          assertEquals( "Object should be updated", a1.getAuthCount(), 1 );
60          assertTrue( "Object should be authorized", a2.isAuthorized() );
61          assertEquals( "Object should be updated", a2.getAuthCount(), 1 );
62  
63          controller.setAuthenticationToken( null );
64          assertFalse( "Object should not be authorized", a1.isAuthorized() );
65          assertEquals( "Object should be updated", a1.getAuthCount(), 2 );
66          assertFalse( "Object should not be authorized", a2.isAuthorized() );
67          assertEquals( "Object should be updated", a2.getAuthCount(), 2 );
68  
69          // Set the decision manager to NOT authorize
70          accessDecisionManager.setDecisionValue( false );
71  
72          // Now install a token, a should be updated
73          controller.setAuthenticationToken( new TestingAuthenticationToken( "USER2", "FOO") );
74          assertFalse( "Object should not be authorized", a1.isAuthorized() );
75          assertEquals( "Object should be updated", a1.getAuthCount(), 3 );
76          assertFalse( "Object should not be authorized", a2.isAuthorized() );
77          assertEquals( "Object should be updated", a2.getAuthCount(), 3 );
78      }
79  
80      public void testSetControlledObjects() {
81  
82          TestAuthorizable a1 = new TestAuthorizable( true );
83          TestAuthorizable a2 = new TestAuthorizable( true );
84          ArrayList goodList = new ArrayList();
85          goodList.add( a1 );
86          goodList.add( a2 );
87  
88          ArrayList badList = new ArrayList();
89          badList.add( new Object() );
90  
91          try {
92              controller.setControlledObjects( badList );
93              fail( "Should reject objects that aren't Authorizable" );
94          } catch( IllegalArgumentException e ) {
95              // expected
96          }
97  
98          controller.setControlledObjects( goodList );
99          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 }