View Javadoc

    1   /* Copyright 2004, 2005 Acegi Technology Pty Limited
    2    *
    3    * Licensed under the Apache License, Version 2.0 (the "License");
    4    * you may not use this file except in compliance with the License.
    5    * You may obtain a copy of the License at
    6    *
    7    *     http://www.apache.org/licenses/LICENSE-2.0
    8    *
    9    * Unless required by applicable law or agreed to in writing, software
    10   * distributed under the License is distributed on an "AS IS" BASIS,
    11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12   * See the License for the specific language governing permissions and
    13   * limitations under the License.
    14   */
    15
    16  package org.acegisecurity.ui.webapp;
    17
    18  import org.acegisecurity.Authentication;
    19  import org.acegisecurity.AuthenticationException;
    20
    21  import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
    22
    23  import org.acegisecurity.ui.WebAuthenticationDetails;
    24
    25  import javax.servlet.FilterConfig;
    26  import javax.servlet.ServletException;
    27  import javax.servlet.http.HttpServletRequest;
    28
    29
    30  /***
    31   * Extends Acegi's AuthenticationProcessingFilter to pick up Netegrity
    32   * Siteminder's headers.
    33   *
    34   * <P>
    35   * Also provides a backup form-based authentication and the ability set source
    36   * key names.
    37   * </p>
    38   *
    39   * <P>
    40   * <B>Siteminder</B> must present two <B>headers</B> to this filter, a username
    41   * and password. You must set the header keys before this filter is used for
    42   * authentication, otherwise Siteminder checks will be skipped. If the
    43   * Siteminder check is unsuccessful (i.e. if the headers are not found), then
    44   * the form parameters will be checked (see next paragraph). This allows
    45   * applications to optionally function even when their Siteminder
    46   * infrastructure is unavailable, as is often the case during development.
    47   * </p>
    48   *
    49   * <P>
    50   * <B>Login forms</B> must present two <B>parameters</B> to this filter: a
    51   * username and password. If not specified, the parameter names to use are
    52   * contained in the static fields {@link #ACEGI_SECURITY_FORM_USERNAME_KEY}
    53   * and {@link #ACEGI_SECURITY_FORM_PASSWORD_KEY}.
    54   * </p>
    55   *
    56   * <P>
    57   * <B>Do not use this class directly.</B> Instead, configure
    58   * <code>web.xml</code> to use the {@link
    59   * org.acegisecurity.util.FilterToBeanProxy}.
    60   * </p>
    61   */
    62  public class SiteminderAuthenticationProcessingFilter
    63      extends AuthenticationProcessingFilter {
    64      //~ Instance fields ========================================================
    65
    66      /*** Form password request key. */
    67      private String formPasswordParameterKey = null;
    68
    69      /*** Form username request key. */
    70      private String formUsernameParameterKey = null;
    71
    72      /*** Siteminder password header key. */
    73      private String siteminderPasswordHeaderKey = null;
    74
    75      /*** Siteminder username header key. */
    76      private String siteminderUsernameHeaderKey = null;
    77
    78      //~ Constructors ===========================================================
    79
    80      /***
    81       * Basic constructor.
    82       */
    83      public SiteminderAuthenticationProcessingFilter() {
    84          super();
    85      }
    86
    87      //~ Methods ================================================================
    88
    89      /***
    90       * @see org.acegisecurity.ui.AbstractProcessingFilter#attemptAuthentication(javax.servlet.http.HttpServletRequest)
    91       */
    92      public Authentication attemptAuthentication(HttpServletRequest request)
    93          throws AuthenticationException {
    94          String username = null;
    95          String password = null;
    96
    97          // Check the Siteminder headers for authentication info
    98          if ((siteminderUsernameHeaderKey != null)
    99              && (siteminderUsernameHeaderKey.length() > 0)
    100             && (siteminderPasswordHeaderKey != null)
    101             && (siteminderPasswordHeaderKey.length() > 0)) {
    102             username = request.getHeader(siteminderUsernameHeaderKey);
    103             password = request.getHeader(siteminderPasswordHeaderKey);
    104         }
    105
    106         // If the Siteminder authentication info wasn't available, then get it
    107         // from the form parameters
    108         if ((username == null) || (username.length() == 0)
    109             || (password == null) || (password.length() == 0)) {
    110             if (logger.isDebugEnabled()) {
    111                 logger.debug(
    112                     "Siteminder headers not found for authentication, so trying to use form values");
    113             }
    114
    115             if ((formUsernameParameterKey != null)
    116                 && (formUsernameParameterKey.length() > 0)) {
    117                 username = request.getParameter(formUsernameParameterKey);
    118             } else {
    119                 username = request.getParameter(ACEGI_SECURITY_FORM_USERNAME_KEY);
    120             }
    121
    122             password = obtainPassword(request);
    123         }
    124
    125         // Convert username and password to upper case. This is normally not a
    126         // good practice but we do it here because Siteminder gives us the username
    127         // in lower case, while most backing systems store it in upper case.
    128         if (username != null) {
    129             username = username.toUpperCase();
    130         } else {
    131             // If username is null, set to blank to avoid a NPE.
    132             username = "";
    133         }
    134
    135         if (password != null) {
    136             password = password.toUpperCase();
    137         } else {
    138             // If password is null, set to blank to avoid a NPE.
    139             password = "";
    140         }
    141
    142         UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username,
    143                 password);
    144
    145         // Allow subclasses to set the "details" property
    146         setDetails(request, authRequest);
    147
    148         // Place the last username attempted into HttpSession for views
    149         request.getSession()
    150                .setAttribute(ACEGI_SECURITY_LAST_USERNAME_KEY, username);
    151
    152         return this.getAuthenticationManager().authenticate(authRequest);
    153     }
    154
    155     /***
    156      * This filter by default responds to <code>/j_acegi_security_check</code>.
    157      *
    158      * @return the default
    159      */
    160     public String getDefaultFilterProcessesUrl() {
    161         return "/j_acegi_security_check";
    162     }
    163
    164     /***
    165      * Returns the form password parameter key.
    166      *
    167      * @return The form password parameter key.
    168      */
    169     public String getFormPasswordParameterKey() {
    170         return formPasswordParameterKey;
    171     }
    172
    173     /***
    174      * Returns the form username parameter key.
    175      *
    176      * @return The form username parameter key.
    177      */
    178     public String getFormUsernameParameterKey() {
    179         return formUsernameParameterKey;
    180     }
    181
    182     /***
    183      * Returns the Siteminder password header key.
    184      *
    185      * @return The Siteminder password header key.
    186      */
    187     public String getSiteminderPasswordHeaderKey() {
    188         return siteminderPasswordHeaderKey;
    189     }
    190
    191     /***
    192      * Returns the Siteminder username header key.
    193      *
    194      * @return The Siteminder username header key.
    195      */
    196     public String getSiteminderUsernameHeaderKey() {
    197         return siteminderUsernameHeaderKey;
    198     }
    199
    200     /***
    201      * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
    202      */
    203     public void init(FilterConfig filterConfig) throws ServletException {}
    204
    205     /***
    206      * Enables subclasses to override the composition of the password, such as
    207      * by including additional values and a separator.
    208      *
    209      * <p>
    210      * This might be used for example if a postcode/zipcode was required in
    211      * addition to the password. A delimiter such as a pipe (|) should be used
    212      * to separate the password and extended value(s). The
    213      * <code>AuthenticationDao</code> will need to generate the expected
    214      * password in a corresponding manner.
    215      * </p>
    216      *
    217      * @param request so that request attributes can be retrieved
    218      *
    219      * @return the password that will be presented in the
    220      *         <code>Authentication</code> request token to the
    221      *         <code>AuthenticationManager</code>
    222      */
    223     protected String obtainPassword(HttpServletRequest request) {
    224         if ((formPasswordParameterKey != null)
    225             && (formPasswordParameterKey.length() > 0)) {
    226             return request.getParameter(formPasswordParameterKey);
    227         } else {
    228             return request.getParameter(ACEGI_SECURITY_FORM_PASSWORD_KEY);
    229         }
    230     }
    231
    232     /***
    233      * Provided so that subclasses may configure what is put into the
    234      * authentication request's details property. The default implementation
    235      * simply constructs {@link WebAuthenticationDetails}.
    236      *
    237      * @param request that an authentication request is being created for
    238      * @param authRequest the authentication request object that should have
    239      *        its details set
    240      */
    241     protected void setDetails(HttpServletRequest request,
    242         UsernamePasswordAuthenticationToken authRequest) {
    243         authRequest.setDetails(new WebAuthenticationDetails(request));
    244     }
    245
    246     /***
    247      * Sets the form password parameter key.
    248      *
    249      * @param key The form password parameter key.
    250      */
    251     public void setFormPasswordParameterKey(final String key) {
    252         this.formPasswordParameterKey = key;
    253     }
    254
    255     /***
    256      * Sets the form username parameter key.
    257      *
    258      * @param key The form username parameter key.
    259      */
    260     public void setFormUsernameParameterKey(final String key) {
    261         this.formUsernameParameterKey = key;
    262     }
    263
    264     /***
    265      * Sets the Siteminder password header key.
    266      *
    267      * @param key The Siteminder password header key.
    268      */
    269     public void setSiteminderPasswordHeaderKey(final String key) {
    270         this.siteminderPasswordHeaderKey = key;
    271     }
    272
    273     /***
    274      * Sets the Siteminder username header key.
    275      *
    276      * @param key The Siteminder username header key.
    277      */
    278     public void setSiteminderUsernameHeaderKey(final String key) {
    279         this.siteminderUsernameHeaderKey = key;
    280     }
    281 }