View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.shiro.authc;
20  
21  import org.apache.log4j.Appender;
22  import org.apache.log4j.Layout;
23  import org.apache.log4j.Logger;
24  import org.apache.log4j.SimpleLayout;
25  import org.apache.log4j.WriterAppender;
26  import org.junit.Before;
27  import org.junit.Test;
28  
29  import java.io.ByteArrayOutputStream;
30  
31  import static org.easymock.EasyMock.*;
32  import static org.junit.Assert.*;
33  
34  
35  /**
36   * @since 0.1
37   */
38  public class AbstractAuthenticatorTest {
39  
40      AbstractAuthenticator abstractAuthenticator;
41      private final SimpleAuthenticationInfo info = new SimpleAuthenticationInfo("user1", "secret", "realmName");
42  
43      private AbstractAuthenticator createAuthcReturnNull() {
44          return new AbstractAuthenticator() {
45              protected AuthenticationInfo doAuthenticate(AuthenticationToken token) throws AuthenticationException {
46                  return null;
47              }
48          };
49      }
50  
51      private AbstractAuthenticator createAuthcReturnValidAuthcInfo() {
52          return new AbstractAuthenticator() {
53              protected AuthenticationInfo doAuthenticate(AuthenticationToken token) throws AuthenticationException {
54                  return info;
55              }
56          };
57      }
58  
59      private AuthenticationToken newToken() {
60          return new UsernamePasswordToken("user1", "secret");
61      }
62  
63      @Before
64      public void setUp() {
65          abstractAuthenticator = createAuthcReturnValidAuthcInfo();
66      }
67  
68      @Test
69      public void newAbstractAuthenticatorSecurityManagerConstructor() {
70          abstractAuthenticator = new AbstractAuthenticator() {
71              protected AuthenticationInfo doAuthenticate(AuthenticationToken token) throws AuthenticationException {
72                  return info;
73              }
74          };
75      }
76  
77  
78      /**
79       * Ensures that the authenticate() method proactively fails if a <tt>null</tt> AuthenticationToken is passed as an
80       * argument.
81       */
82      @Test(expected = IllegalArgumentException.class)
83      public void authenticateWithNullArgument() {
84          abstractAuthenticator.authenticate(null);
85      }
86  
87      /**
88       * Ensures that the authenticate() method throws an AuthenticationException if the subclass returns <tt>null</tt>
89       * as the return value to the doAuthenticate() method.
90       */
91      @Test(expected = AuthenticationException.class)
92      public void throwAuthenticationExceptionIfDoAuthenticateReturnsNull() {
93          abstractAuthenticator = createAuthcReturnNull();
94          abstractAuthenticator.authenticate(newToken());
95      }
96  
97      /**
98       * Ensures a non-null <tt>Subject</tt> instance is returned from the authenticate() method after a valid
99       * authentication attempt (i.e. the subclass's doAuthenticate implementation returns a valid, non-null
100      * AuthenticationInfo object).
101      */
102     @Test
103     public void nonNullAuthenticationInfoAfterAuthenticate() {
104         AuthenticationInfo authcInfo = abstractAuthenticator.authenticate(newToken());
105         assertNotNull(authcInfo);
106     }
107 
108     @Test
109     public void notifySuccessAfterDoAuthenticate() {
110         AuthenticationListener mockListener = createMock(AuthenticationListener.class);
111         abstractAuthenticator.getAuthenticationListeners().add(mockListener);
112         AuthenticationToken token = newToken();
113         mockListener.onSuccess(token, info);
114 
115         replay(mockListener);
116         abstractAuthenticator.authenticate(token);
117         verify(mockListener);
118     }
119 
120     @Test
121     public void notifyFailureAfterDoAuthenticateThrowsAuthenticationException() {
122         AuthenticationListener mockListener = createMock(AuthenticationListener.class);
123         AuthenticationToken token = newToken();
124 
125         final AuthenticationException ae = new AuthenticationException("dummy exception to test notification");
126 
127         abstractAuthenticator = new AbstractAuthenticator() {
128             protected AuthenticationInfo doAuthenticate(AuthenticationToken token) throws AuthenticationException {
129                 throw ae;
130             }
131         };
132         abstractAuthenticator.getAuthenticationListeners().add(mockListener);
133 
134         mockListener.onFailure(token, ae);
135         replay(mockListener);
136 
137         boolean exceptionThrown = false;
138         try {
139             abstractAuthenticator.authenticate(token);
140         } catch (AuthenticationException e) {
141             exceptionThrown = true;
142             assertEquals(e, ae);
143         }
144         verify(mockListener);
145 
146         if (!exceptionThrown) {
147             fail("An AuthenticationException should have been thrown during the notifyFailure test case.");
148         }
149     }
150 
151     @Test(expected = AuthenticationException.class)
152     public void notifyFailureAfterDoAuthenticateThrowsNonAuthenticationException() {
153         abstractAuthenticator = new AbstractAuthenticator() {
154             protected AuthenticationInfo doAuthenticate(AuthenticationToken token) throws AuthenticationException {
155                 throw new IllegalArgumentException("not an AuthenticationException subclass");
156             }
157         };
158         AuthenticationToken token = newToken();
159         abstractAuthenticator.authenticate(token);
160     }
161 
162     @Test
163     public void logExceptionAfterDoAuthenticateThrowsNonAuthenticationException() {
164         Logger logger = Logger.getLogger(AbstractAuthenticator.class);
165 
166         // NOTE: log4j is a test dependency
167         ByteArrayOutputStream out = new ByteArrayOutputStream();
168         Layout layout = new SimpleLayout();
169         Appender appender = new WriterAppender(layout, out);
170         logger.addAppender(appender);
171 
172         final String expectedExceptionMessage = "exception thrown for test logExceptionAfterDoAuthenticateThrowsNonAuthenticationException";
173 
174         abstractAuthenticator = new AbstractAuthenticator() {
175             protected AuthenticationInfo doAuthenticate(AuthenticationToken token) throws AuthenticationException {
176                 throw new IllegalArgumentException(expectedExceptionMessage);
177             }
178         };
179         AuthenticationToken token = newToken();
180 
181         try{
182             abstractAuthenticator.authenticate(token);
183             fail("the expected AuthenticationException was not thrown");
184         }catch(AuthenticationException expectedException){
185         }
186 
187         String logMsg = out.toString();
188         assertTrue(logMsg.contains("WARN"));
189         assertTrue(logMsg.contains("java.lang.IllegalArgumentException: "+ expectedExceptionMessage));
190 
191         logger.removeAppender(appender);
192     }
193 
194 }