View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.module.acegi.filters.http;
8   
9   import org.mule.api.MuleEvent;
10  import org.mule.api.MuleMessage;
11  import org.mule.api.config.MuleProperties;
12  import org.mule.api.lifecycle.InitialisationException;
13  import org.mule.api.security.Authentication;
14  import org.mule.api.security.SecurityContext;
15  import org.mule.api.security.SecurityException;
16  import org.mule.api.security.SecurityProviderNotFoundException;
17  import org.mule.api.security.UnauthorisedException;
18  import org.mule.api.security.UnknownAuthenticationTypeException;
19  import org.mule.api.security.UnsupportedAuthenticationSchemeException;
20  import org.mule.config.i18n.CoreMessages;
21  import org.mule.module.acegi.AcegiAuthenticationAdapter;
22  import org.mule.module.acegi.i18n.AcegiMessages;
23  import org.mule.security.AbstractEndpointSecurityFilter;
24  import org.mule.transport.http.HttpConnector;
25  import org.mule.transport.http.HttpConstants;
26  
27  import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
28  import org.apache.commons.codec.binary.Base64;
29  import org.apache.commons.logging.Log;
30  import org.apache.commons.logging.LogFactory;
31  
32  /**
33   * <code>HttpBasicAuthenticationFilter</code> TODO
34   */
35  public class HttpBasicAuthenticationFilter extends AbstractEndpointSecurityFilter
36  {
37      /**
38       * logger used by this class
39       */
40      protected static final Log logger = LogFactory.getLog(HttpBasicAuthenticationFilter.class);
41  
42      private String realm;
43  
44      private boolean realmRequired = true;
45  
46      public HttpBasicAuthenticationFilter()
47      {
48          super();
49      }
50  
51      public HttpBasicAuthenticationFilter(String realm)
52      {
53          this.realm = realm;
54      }
55  
56      @Override
57      protected void doInitialise() throws InitialisationException
58      {
59          if (realm == null)
60          {
61              if (isRealmRequired())
62              {
63                  throw new InitialisationException(AcegiMessages.authRealmMustBeSetOnFilter(), this);
64              }
65              else
66              {
67                  logger.warn("There is no security realm set, using default: null");
68              }
69          }
70      }
71  
72      public String getRealm()
73      {
74          return realm;
75      }
76  
77      public void setRealm(String realm)
78      {
79          this.realm = realm;
80      }
81  
82      public boolean isRealmRequired()
83      {
84          return realmRequired;
85      }
86  
87      public void setRealmRequired(boolean realmRequired)
88      {
89          this.realmRequired = realmRequired;
90      }
91  
92      /**
93       * Authenticates the current message if authenticate is set to true. This method
94       * will always populate the secure context in the session
95       *
96       * @param event the current message recieved
97       * @throws org.mule.api.security.SecurityException if authentication fails
98       */
99      @Override
100     public void authenticateInbound(MuleEvent event)
101         throws SecurityException, SecurityProviderNotFoundException, UnknownAuthenticationTypeException
102     {
103         String header = event.getMessage().getInboundProperty(HttpConstants.HEADER_AUTHORIZATION);
104 
105         if (logger.isDebugEnabled())
106         {
107             logger.debug("Authorization header: " + header);
108         }
109 
110         if ((header != null) && header.startsWith("Basic "))
111         {
112             String base64Token = header.substring(6);
113             String token = new String(Base64.decodeBase64(base64Token.getBytes()));
114 
115             String username = "";
116             String password = "";
117             int delim = token.indexOf(":");
118 
119             if (delim != -1)
120             {
121                 username = token.substring(0, delim);
122                 password = token.substring(delim + 1);
123             }
124 
125             UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
126                 username, password);
127             authRequest.setDetails(event.getMessage().getInboundProperty(MuleProperties.MULE_ENDPOINT_PROPERTY));
128 
129             Authentication authResult;
130 
131             Authentication authentication = new AcegiAuthenticationAdapter(authRequest);
132 
133             try
134             {
135                 authResult = getSecurityManager().authenticate(authentication);
136             }
137             catch (UnauthorisedException e)
138             {
139                 // Authentication failed
140                 if (logger.isDebugEnabled())
141                 {
142                     logger.debug("Authentication request for user: " + username + " failed: " + e.toString());
143                 }
144                 setUnauthenticated(event);
145                 throw new UnauthorisedException(CoreMessages.authFailedForUser(username), e);
146             }
147 
148             // Authentication success
149             if (logger.isDebugEnabled())
150             {
151                 logger.debug("Authentication success: " + authResult.toString());
152             }
153 
154             SecurityContext context = getSecurityManager().createSecurityContext(authResult);
155             context.setAuthentication(authResult);
156             event.getSession().setSecurityContext(context);
157         }
158         else if (header == null)
159         {
160             setUnauthenticated(event);
161             throw new UnauthorisedException(event, event.getSession().getSecurityContext(), this);
162         }
163         else
164         {
165             setUnauthenticated(event);
166             throw new UnsupportedAuthenticationSchemeException(
167                 AcegiMessages.basicFilterCannotHandleHeader(header),event);
168         }
169     }
170 
171     protected void setUnauthenticated(MuleEvent event)
172     {
173         String realmHeader = "Basic realm=";
174         if (realm != null)
175         {
176             realmHeader += "\"" + realm + "\"";
177         }
178         MuleMessage msg = event.getMessage();
179         msg.setOutboundProperty(HttpConstants.HEADER_WWW_AUTHENTICATE, realmHeader);
180         msg.setOutboundProperty(HttpConnector.HTTP_STATUS_PROPERTY, HttpConstants.SC_UNAUTHORIZED);
181     }
182 
183     /**
184      * Authenticates the current message if authenticate is set to true. This method
185      * will always populate the secure context in the session
186      *
187      * @param event the current event being dispatched
188      * @throws org.mule.api.security.SecurityException if authentication fails
189      */
190     @Override
191     public void authenticateOutbound(MuleEvent event)
192         throws SecurityException, SecurityProviderNotFoundException
193     {
194         SecurityContext securityContext = event.getSession().getSecurityContext();
195         if (securityContext == null)
196         {
197             if (isAuthenticate())
198             {
199                 throw new UnauthorisedException(event, securityContext, this);
200             }
201             else
202             {
203                 return;
204             }
205         }
206 
207         Authentication auth = securityContext.getAuthentication();
208         if (isAuthenticate())
209         {
210             auth = getSecurityManager().authenticate(auth);
211             if (logger.isDebugEnabled())
212             {
213                 logger.debug("Authentication success: " + auth.toString());
214             }
215         }
216 
217         StringBuffer header = new StringBuffer(128);
218         header.append("Basic ");
219         String token = auth.getCredentials().toString();
220         header.append(new String(Base64.encodeBase64(token.getBytes())));
221 
222         event.getMessage().setOutboundProperty(HttpConstants.HEADER_AUTHORIZATION, header.toString());
223     }
224 }