View Javadoc
1   /**
2    * Waffle (https://github.com/dblock/waffle)
3    *
4    * Copyright (c) 2010 - 2015 Application Security, Inc.
5    *
6    * All rights reserved. This program and the accompanying materials
7    * are made available under the terms of the Eclipse Public License v1.0
8    * which accompanies this distribution, and is available at
9    * http://www.eclipse.org/legal/epl-v10.html
10   *
11   * Contributors:
12   *     Application Security, Inc.
13   */
14  /**
15   * 
16   */
17  package waffle.spring;
18  
19  import java.io.IOException;
20  
21  import javax.servlet.ServletException;
22  import javax.servlet.http.HttpServletRequest;
23  import javax.servlet.http.HttpServletResponse;
24  
25  import org.slf4j.Logger;
26  import org.slf4j.LoggerFactory;
27  import org.springframework.security.access.AccessDeniedException;
28  import org.springframework.security.authentication.AuthenticationManager;
29  import org.springframework.security.core.Authentication;
30  import org.springframework.security.core.AuthenticationException;
31  import org.springframework.security.core.context.SecurityContextHolder;
32  import org.springframework.security.web.access.AccessDeniedHandler;
33  import org.springframework.security.web.authentication.AuthenticationFailureHandler;
34  import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
35  
36  /**
37   * 
38   * 
39   * <p>
40   * Supports optional injection of spring security entities, allowing Waffle to act as an interface towards an identity
41   * provider(the AD).
42   * </p>
43   * 
44   * <i>Below mentioned entities are verified to be set before invoked, inherited entities are not.</i>
45   * 
46   * <ul>
47   * <li>
48   * The <code>AuthenticationManager</code> allows for the service provider to authorize the principal.</li>
49   * 
50   * <li>
51   * The <code>authenticationSuccessHandler</code> allows for the service provider to further populate the
52   * {@link org.springframework.security.core.Authentication Authentication} object.</li>
53   * 
54   * <li>
55   * The <code>AuthenticationFailureHandler</code> is called if the AuthenticationManager throws an
56   * {@link org.springframework.security.core.AuthenticationException AuthenticationException}.</li>
57   * 
58   * <li>
59   * The <code>AccessDeniedHandler</code> is called if the AuthenticationManager throws an
60   * {@link org.springframework.security.access.AccessDeniedException AccessDeniedException}.</li>
61   * </ul>
62   * Example configuration:
63   * 
64   * <pre>
65   * {@code
66   * <bean id="waffleNegotiateSecurityFilter"
67   * 		class="waffle.spring.DelegatingNegotiateSecurityFilter"
68   * 		scope="tenant">
69   * 		<property name="allowGuestLogin" value="false" />
70   * 		<property name="Provider" ref="waffleSecurityFilterProviderCollection" />
71   * 		<property name="authenticationManager" ref="authenticationManager" />
72   * 		<property name="authenticationSuccessHandler" ref="authenticationSuccessHandler" />
73   * 		<property name="authenticationFailureHandler" ref="authenticationFailureHandler" />
74   * 		<property name="accessDeniedHandler" ref="accessDeniedHandler" />
75   * 		<property name="defaultGrantedAuthority">
76   * 			<null />
77   * 		</property>
78   * 	</bean>
79   * </code>
80   * }
81   * </pre>
82   */
83  public class DelegatingNegotiateSecurityFilter extends NegotiateSecurityFilter {
84      
85      /** The Constant LOGGER. */
86      private static final Logger          LOGGER = LoggerFactory.getLogger(NegotiateSecurityFilter.class);
87  
88      /** The authentication manager. */
89      private AuthenticationManager        authenticationManager;
90      
91      /** The authentication success handler. */
92      private AuthenticationSuccessHandler authenticationSuccessHandler;
93      
94      /** The authentication failure handler. */
95      private AuthenticationFailureHandler authenticationFailureHandler;
96      
97      /** The access denied handler. */
98      private AccessDeniedHandler          accessDeniedHandler;
99  
100     /**
101      * Gets the access denied handler.
102      *
103      * @return the accessDeniedHandler
104      */
105     public AccessDeniedHandler getAccessDeniedHandler() {
106         return this.accessDeniedHandler;
107     }
108 
109     /**
110      * Sets the access denied handler.
111      *
112      * @param accessDeniedHandler
113      *            the accessDeniedHandler to set
114      */
115     public void setAccessDeniedHandler(final AccessDeniedHandler accessDeniedHandler) {
116         this.accessDeniedHandler = accessDeniedHandler;
117     }
118 
119     /**
120      * Gets the authentication failure handler.
121      *
122      * @return the authenticationFailureHandler
123      */
124     public AuthenticationFailureHandler getAuthenticationFailureHandler() {
125         return this.authenticationFailureHandler;
126     }
127 
128     /**
129      * Sets the authentication failure handler.
130      *
131      * @param authenticationFailureHandler
132      *            the authenticationFailureHandler to set
133      */
134     public void setAuthenticationFailureHandler(final AuthenticationFailureHandler authenticationFailureHandler) {
135         this.authenticationFailureHandler = authenticationFailureHandler;
136     }
137 
138     /**
139      * Instantiates a new delegating negotiate security filter.
140      */
141     public DelegatingNegotiateSecurityFilter() {
142         super();
143         DelegatingNegotiateSecurityFilter.LOGGER.debug("[waffle.spring.NegotiateSecurityFilter] loaded");
144     }
145 
146     /* (non-Javadoc)
147      * @see waffle.spring.NegotiateSecurityFilter#setAuthentication(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.springframework.security.core.Authentication)
148      */
149     @Override
150     protected boolean setAuthentication(final HttpServletRequest request, final HttpServletResponse response,
151             final Authentication authentication) {
152         try {
153             if (this.authenticationManager != null) {
154                 this.logger.debug("Delegating to custom authenticationmanager");
155                 final Authentication customAuthentication = this.authenticationManager.authenticate(authentication);
156                 SecurityContextHolder.getContext().setAuthentication(customAuthentication);
157             }
158             if (this.authenticationSuccessHandler != null) {
159                 try {
160                     this.authenticationSuccessHandler.onAuthenticationSuccess(request, response, authentication);
161                 } catch (final IOException e) {
162                     this.logger.warn("Error calling authenticationSuccessHandler: " + e.getMessage());
163                     return false;
164                 } catch (final ServletException e) {
165                     this.logger.warn("Error calling authenticationSuccessHandler: " + e.getMessage());
166                     return false;
167                 }
168             }
169         } catch (final AuthenticationException e) {
170 
171             this.logger.warn("Error authenticating user in custom authenticationmanager: " + e.getMessage());
172             this.sendAuthenticationFailed(request, response, e);
173             return false;
174         } catch (final AccessDeniedException e) {
175             this.logger.warn("Error authorizing user in custom authenticationmanager: " + e.getMessage());
176             this.sendAccessDenied(request, response, e);
177             return false;
178         }
179         return true;
180     }
181 
182     /* (non-Javadoc)
183      * @see waffle.spring.NegotiateSecurityFilter#afterPropertiesSet()
184      */
185     @Override
186     public void afterPropertiesSet() throws ServletException {
187         super.afterPropertiesSet();
188 
189         if (this.getProvider() == null) {
190             throw new ServletException("Missing NegotiateSecurityFilter.Provider");
191         }
192     }
193 
194     /**
195      * Forward to authenticationFailureHandler.
196      *
197      * @param request
198      *            the request
199      * @param response
200      *            HTTP Response
201      * @param ae
202      *            the ae
203      */
204     private void sendAuthenticationFailed(final HttpServletRequest request, final HttpServletResponse response,
205             final AuthenticationException ae) {
206         if (this.authenticationFailureHandler != null) {
207             try {
208                 this.authenticationFailureHandler.onAuthenticationFailure(request, response, ae);
209                 return;
210             } catch (final IOException e) {
211                 DelegatingNegotiateSecurityFilter.LOGGER.warn("IOException invoking authenticationFailureHandler: " + e.getMessage());
212             } catch (final ServletException e) {
213                 DelegatingNegotiateSecurityFilter.LOGGER.warn("ServletException invoking authenticationFailureHandler: " + e.getMessage());
214             }
215         }
216         super.sendUnauthorized(response, true);
217     }
218 
219     /**
220      * Forward to accessDeniedHandler.
221      *
222      * @param request
223      *            the request
224      * @param response
225      *            HTTP Response
226      * @param ae
227      *            the ae
228      */
229     private void sendAccessDenied(final HttpServletRequest request, final HttpServletResponse response,
230             final AccessDeniedException ae) {
231         if (this.accessDeniedHandler != null) {
232             try {
233                 this.accessDeniedHandler.handle(request, response, ae);
234                 return;
235             } catch (final IOException e) {
236                 DelegatingNegotiateSecurityFilter.LOGGER.warn("IOException invoking accessDeniedHandler: " + e.getMessage());
237             } catch (final ServletException e) {
238                 DelegatingNegotiateSecurityFilter.LOGGER.warn("ServletException invoking accessDeniedHandler: " + e.getMessage());
239             }
240         }
241         // fallback
242         this.sendUnauthorized(response, true);
243     }
244 
245     /**
246      * Gets the authentication success handler.
247      *
248      * @return the authenticationSuccessHandler
249      */
250     public AuthenticationSuccessHandler getAuthenticationSuccessHandler() {
251         return this.authenticationSuccessHandler;
252     }
253 
254     /**
255      * Sets the authentication success handler.
256      *
257      * @param authenticationSuccessHandler
258      *            the authenticationSuccessHandler to set
259      */
260     public void setAuthenticationSuccessHandler(final AuthenticationSuccessHandler authenticationSuccessHandler) {
261         this.authenticationSuccessHandler = authenticationSuccessHandler;
262     }
263 
264     /**
265      * Gets the authentication manager.
266      *
267      * @return the authenticationManager
268      */
269     public AuthenticationManager getAuthenticationManager() {
270         return this.authenticationManager;
271     }
272 
273     /**
274      * Sets the authentication manager.
275      *
276      * @param authenticationManager
277      *            the authenticationManager to set
278      */
279     public void setAuthenticationManager(final AuthenticationManager authenticationManager) {
280         this.authenticationManager = authenticationManager;
281     }
282 
283 }