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.providers.jaas;
    17
    18  import org.acegisecurity.Authentication;
    19  import org.acegisecurity.context.SecurityContextHolder;
    20
    21  import org.apache.commons.logging.Log;
    22  import org.apache.commons.logging.LogFactory;
    23
    24  import java.util.Map;
    25
    26  import javax.security.auth.Subject;
    27  import javax.security.auth.callback.CallbackHandler;
    28  import javax.security.auth.login.LoginException;
    29  import javax.security.auth.spi.LoginModule;
    30
    31
    32  /***
    33   * An implementation of {@link LoginModule} that uses an Acegi Security
    34   * {@link org.acegisecurity.context.SecurityContext SecurityContext}
    35   * to provide authentication. <br />
    36   * This LoginModule provides opposite functionality to the {@link
    37   * JaasAuthenticationProvider} API, and should not really be used in
    38   * conjunction with it. <br />
    39   * The {@link JaasAuthenticationProvider} allows Acegi to authenticate against
    40   * Jaas. <br />
    41   * The SecurityContextLoginModule allows a Jaas based application to
    42   * authenticate against Acegi. If there is no Authentication in the {@link
    43   * SecurityContextHolder} the login() method will throw a LoginException by
    44   * default. This functionality can be changed with the
    45   * <tt>ignoreMissingAuthentication</tt> option by setting it to "true".
    46   * Setting  ignoreMissingAuthentication=true will tell the
    47   * SecurityContextLoginModule to simply return false and be ignored if the
    48   * authentication is null.
    49   *
    50   * @author Brian Moseley
    51   * @author Ray Krueger
    52   */
    53  public class SecurityContextLoginModule implements LoginModule {
    54      //~ Static fields/initializers =============================================
    55
    56      private static final Log log = LogFactory.getLog(SecurityContextLoginModule.class);
    57
    58      //~ Instance fields ========================================================
    59
    60      private Authentication authen;
    61      private Subject subject;
    62      private boolean ignoreMissingAuthentication = false;
    63
    64      //~ Methods ================================================================
    65
    66      /***
    67       * Abort the authentication process by forgetting the Acegi Security
    68       * <code>Authentication</code>.
    69       *
    70       * @return true if this method succeeded, or false if this
    71       *         <code>LoginModule</code> should be ignored.
    72       *
    73       * @exception LoginException if the abort fails
    74       */
    75      public boolean abort() throws LoginException {
    76          if (authen == null) {
    77              return false;
    78          }
    79
    80          authen = null;
    81
    82          return true;
    83      }
    84
    85      /***
    86       * Authenticate the <code>Subject</code> (phase two) by adding the Acegi
    87       * Security <code>Authentication</code> to the <code>Subject</code>'s
    88       * principals.
    89       *
    90       * @return true if this method succeeded, or false if this
    91       *         <code>LoginModule</code> should be ignored.
    92       *
    93       * @exception LoginException if the commit fails
    94       */
    95      public boolean commit() throws LoginException {
    96          if (authen == null) {
    97              return false;
    98          }
    99
    100         subject.getPrincipals().add(authen);
    101
    102         return true;
    103     }
    104
    105     /***
    106      * Initialize this <code>LoginModule</code>. Ignores the callback handler,
    107      * since the code establishing the <code>LoginContext</code> likely won't
    108      * provide one that understands Acegi Security. Also ignores the
    109      * <code>sharedState</code> and <code>options</code> parameters, since
    110      * none are recognized.
    111      *
    112      * @param subject the <code>Subject</code> to be authenticated. <p>
    113      * @param callbackHandler is ignored
    114      * @param sharedState is ignored
    115      * @param options are ignored
    116      */
    117     public void initialize(Subject subject, CallbackHandler callbackHandler,
    118         Map sharedState, Map options) {
    119         this.subject = subject;
    120
    121         if (options != null) {
    122             ignoreMissingAuthentication = "true".equals(options.get(
    123                         "ignoreMissingAuthentication"));
    124         }
    125     }
    126
    127     /***
    128      * Authenticate the <code>Subject</code> (phase one) by extracting the
    129      * Acegi Security <code>Authentication</code> from the current
    130      * <code>SecurityContext</code>.
    131      *
    132      * @return true if the authentication succeeded, or false if this
    133      *         <code>LoginModule</code> should be ignored.
    134      *
    135      * @throws LoginException if the authentication fails
    136      */
    137     public boolean login() throws LoginException {
    138         authen = SecurityContextHolder.getContext().getAuthentication();
    139
    140         if (authen == null) {
    141             String msg = "Login cannot complete, authentication not found in security context";
    142
    143             if (ignoreMissingAuthentication) {
    144                 log.warn(msg);
    145
    146                 return false;
    147             } else {
    148                 throw new LoginException(msg);
    149             }
    150         }
    151
    152         return true;
    153     }
    154
    155     /***
    156      * Log out the <code>Subject</code>.
    157      *
    158      * @return true if this method succeeded, or false if this
    159      *         <code>LoginModule</code> should be ignored.
    160      *
    161      * @exception LoginException if the logout fails
    162      */
    163     public boolean logout() throws LoginException {
    164         if (authen == null) {
    165             return false;
    166         }
    167
    168         subject.getPrincipals().remove(authen);
    169         authen = null;
    170
    171         return true;
    172     }
    173
    174     Authentication getAuthentication() {
    175         return authen;
    176     }
    177
    178     Subject getSubject() {
    179         return subject;
    180     }
    181 }