View Javadoc

1   /*
2   jGuard is a security framework based on top of jaas (java authentication and authorization security).
3   it is written for web applications, to resolve simply, access control problems.
4   version $Name$
5   http://sourceforge.net/projects/jguard/
6   
7   Copyright (C) 2004  Charles GAY
8   
9   This library is free software; you can redistribute it and/or
10  modify it under the terms of the GNU Lesser General Public
11  License as published by the Free Software Foundation; either
12  version 2.1 of the License, or (at your option) any later version.
13  
14  This library is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  Lesser General Public License for more details.
18  
19  You should have received a copy of the GNU Lesser General Public
20  License along with this library; if not, write to the Free Software
21  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  
23  
24  jGuard project home page:
25  http://sourceforge.net/projects/jguard/
26  
27  */
28  
29  package net.sf.jguard.core.authentication;
30  
31  import net.sf.jguard.core.CoreConstants;
32  import net.sf.jguard.core.authentication.bindings.*;
33  import net.sf.jguard.core.authentication.callbacks.AuthenticationSchemeHandlerCallback;
34  import net.sf.jguard.core.authentication.callbacks.InetAddressCallback;
35  import net.sf.jguard.core.authentication.credentials.JGuardCredential;
36  import net.sf.jguard.core.authentication.schemes.AuthenticationSchemeHandler;
37  import net.sf.jguard.core.authentication.schemes.HookFormSchemeHandler;
38  import org.slf4j.Logger;
39  import org.slf4j.LoggerFactory;
40  
41  import javax.security.auth.Subject;
42  import javax.security.auth.callback.*;
43  import javax.security.auth.login.LoginException;
44  import java.security.Permission;
45  import java.util.*;
46  
47  
48  /**
49   * Authenticate a user in an application with a specific {@link AuthenticationBindings}.
50   *
51   * @author <a href="mailto:diabolo512@users.sourceforge.net">Charles Gay</a>
52   * @since 1.1
53   */
54  public class AuthenticationServicePoint {
55      private static final String PASSWORD = "password";
56      private static final String LOGIN = "login";
57  
58  
59      private static final Logger logger = LoggerFactory.getLogger(AuthenticationServicePoint.class.getName());
60  
61  
62      /**
63       * return <b>true</b> if the user <b>tries</b> to answer to an authentication challenge.
64       *
65       * @param context
66       * @param factory
67       * @return
68       */
69      public static boolean answerToChallenge(AccessContext context, AuthenticationBindingsFactory factory) {
70          List<AuthenticationSchemeHandler> authSchemeHandlers = factory.getAuthenticationSchemeHandlers();
71          for (AuthenticationSchemeHandler handler : authSchemeHandlers) {
72              boolean answerToChallenge = handler.answerToChallenge(context);
73              if (answerToChallenge) {
74                  return true;
75              }
76          }
77  
78          return false;
79      }
80  
81      /**
82       * authenticate the user.
83       * if the {@link AuthenticationBindings} implementation implements the
84       * StatefulAuthenticationBindings interface, this method removes a possible old {@link AuthenticationUtils} object,
85       * invalidate the session, create a new one, and bound the new Authenticationutils to it.
86       */
87      public static AuthenticationUtils authenticate(AuthenticationBindings authenticationBindings, String applicationName, String authenticationScope) throws AuthenticationException {
88          authenticationBindings.setRequestAttribute(CoreConstants.REGISTRATION_DONE, Boolean.FALSE);
89  
90          //we grab the CallbackHandler to communicate during authentication with the user
91          CallbackHandler cbh = authenticationBindings.getCallbackHandler();
92          AuthenticationUtils authNUtils = null;
93          try {
94              //we grab the wrapper object which link the user via its session with authentication
95              authNUtils = authenticationBindings.getAuthenticationUtils();
96  
97              //we use the wrapper object bound to user with the dedicated object(callabckHandler)
98              //to communicate with him to authenticate
99              authNUtils.login(applicationName, cbh);
100 
101             //for security reasons(man-in-the-middle attack for sessionID cookie),
102             //we remove the old session if authentication is successfull
103             //and create a new session
104 
105             if (authenticationBindings instanceof StatefulAuthenticationBindings) {
106                 Permission lastAccessDeniedPermission = null;
107                 //we remove this variable before invalidate the session
108                 //to prevent the session listener to erase the subject
109                 ((StatefulAuthenticationBindings) authenticationBindings).removeSessionAttribute(CoreConstants.AUTHN_UTILS);
110                 lastAccessDeniedPermission = (Permission) ((StatefulAuthenticationBindings) authenticationBindings).getSessionAttribute(CoreConstants.LAST_ACCESS_DENIED_PERMISSION);
111                 ((StatefulAuthenticationBindings) authenticationBindings).invalidateSession();
112 
113                 ((StatefulAuthenticationBindings) authenticationBindings).setSessionAttribute(CoreConstants.AUTHN_UTILS, authNUtils);
114                 ((StatefulAuthenticationBindings) authenticationBindings).setSessionAttribute(CoreConstants.LAST_ACCESS_DENIED_PERMISSION, lastAccessDeniedPermission);
115 
116             }
117             AuthenticationSchemeHandler authSchemeHandler = getAuthenticationSchemeHandler(authNUtils.getSubject(), authenticationBindings.getAuthenticationBindingsFactory());
118             authSchemeHandler.authenticationSucceed(authenticationBindings.getContext());
119             authNUtils.setStatus(AuthenticationStatus.SUCCESS);
120             return authNUtils;
121 
122         } catch (AuthenticationContinueException ace) {
123             //the current AuthenticationScheme needs multiple roundtrips
124             logger.debug("authentication is not yet complete. a new exchange between client and server is required " + ace.getMessage());
125             authNUtils.setStatus(AuthenticationStatus.CONTINUE);
126             return authNUtils;
127         } catch (AuthenticationChallengeException ace) {
128             //the callbackHandle handle this case. we only need here to go back the call to the user
129             logger.debug("authentication challenge built. a new exchange between client and server is required " + ace.getMessage());
130             authNUtils.setStatus(AuthenticationStatus.FAILURE);
131             return authNUtils;
132 
133         } catch (LoginException e) {
134 
135             logger.debug("authentication failed " + e.getMessage(), e);
136             String messageError = null;
137             messageError = e.getLocalizedMessage();
138             //we store in the user' session the reason the authentication failed
139             authenticationBindings.setRequestAttribute(CoreConstants.LOGIN_EXCEPTION_MESSAGE, messageError);
140             authenticationBindings.setRequestAttribute(CoreConstants.LOGIN_EXCEPTION_CLASS, e.getClass());
141             AuthenticationSchemeHandler authSchemeHandler = (AuthenticationSchemeHandler) authenticationBindings.getRequestAttribute(CoreConstants.AUTHENTICATION_SCHEME_HANDLER);
142             authSchemeHandler.authenticationFailed(authenticationBindings.getContext());
143             authNUtils.setStatus(AuthenticationStatus.FAILURE);
144             return authNUtils;
145 
146         }
147     }
148 
149     /**
150      * grab into the {@link Subject} the name of the AuthenticationSchemeHandler,
151      * to select among ones registered into the {@link AuthenticationBindings} and return it.
152      *
153      * @param subject
154      * @return
155      */
156     public static AuthenticationSchemeHandler getAuthenticationSchemeHandler(Subject subject, AuthenticationBindingsFactory authNBindingsFactory) {
157         String authSchemeHandlerName = getAuthSchemeHandlerName(subject);
158         if (authSchemeHandlerName == null) {
159             throw new IllegalArgumentException(" Subject does not contains a JGuardCredential with a key='authSchemeHandlerName' and a value not null ");
160         }
161         List<AuthenticationSchemeHandler> authSchemeHandlers = authNBindingsFactory.getAuthenticationSchemeHandlers();
162         AuthenticationSchemeHandler authSchemeHandler = null;
163         for (AuthenticationSchemeHandler authHandler : authSchemeHandlers) {
164             if (authSchemeHandlerName.equals(authHandler.getName())) {
165                 authSchemeHandler = authHandler;
166                 break;
167             }
168         }
169         return authSchemeHandler;
170     }
171 
172     /**
173      * authSchemeHandler name is stored into the Subject credentials set.
174      *
175      * @param subject
176      * @return
177      */
178     private static String getAuthSchemeHandlerName(Subject subject) {
179         Set<JGuardCredential> credentials = subject.getPublicCredentials(JGuardCredential.class);
180         for (JGuardCredential cred : credentials) {
181             if (CoreConstants.AUTHENTICATION_SCHEME_HANDLER_NAME.equals(cred.getName())) {
182                 return (String) cred.getValue();
183             }
184         }
185         return null;
186     }
187 
188     /**
189      * impersonate the current user with the provided callbacks.
190      * note that the user present in the authenticationBindings does not change.
191      * a wrapping mechanism for authenticationSchemeHandler and AuthenticationBindings impersonate
192      * the user, but the underlying authenticationBindings contains the real user.
193      *
194      * @param authenticationBindings
195      * @param authHandlers
196      * @param applicationName
197      * @param callbacks
198      * @param authenticationScope
199      * @return
200      */
201     public static AuthenticationUtils authenticateWithImpersonation(AuthenticationBindings authenticationBindings, List<AuthenticationSchemeHandler> authHandlers, String applicationName, List<Callback> callbacks, String authenticationScope) throws AuthenticationException {
202         AuthenticationSchemeHandlerCallback cb = new AuthenticationSchemeHandlerCallback();
203         cb.setAuthenticationSchemeHandlerName("HOOK");
204         callbacks.add(cb);
205         ImpersonationAuthenticationBindings impersonatedAuthenticationBindings = null;
206         if (authenticationBindings instanceof StatefulAuthenticationBindings) {
207             impersonatedAuthenticationBindings = new StatefulImpersonationAuthenticationBindings(authenticationBindings, callbacks);
208         } else {
209             impersonatedAuthenticationBindings = new ImpersonationAuthenticationBindings(authenticationBindings, callbacks);
210         }
211         impersonatedAuthenticationBindings.addAuthenticationSchemeHandlerToFactory(authHandlers);
212         return AuthenticationServicePoint.authenticate(impersonatedAuthenticationBindings, applicationName, authenticationScope);
213     }
214 
215     /**
216      * impersonate the current user as a Guest user with the related credentials.
217      * it set the NameCallback to <b>guest<b/>,the PasswordCallback to <b>guest</b>,
218      * the InetAddressCallback host address and host name to 127.0.0.1 and localhost.
219      * note that the user present in the authenticationBindings does not change.
220      * a wrapping mechanism for authenticationSchemeHandler and AuthenticationBindings impersonate
221      * the user as a guest, but the underlying authenticationBindings contains the real user.
222      *
223      * @param authenticationBindings underlying authenticationBindings which contains the <b>real</b>
224      * @param applicationName
225      * @param authenticationScope    user.
226      * @return
227      */
228     public static AuthenticationUtils impersonateAsGuest(AuthenticationBindings authenticationBindings, String applicationName, String authenticationScope) throws AuthenticationException {
229 
230         List<Callback> callbacks = new ArrayList<Callback>(4);
231         NameCallback nameCallback = new NameCallback(LOGIN);
232         nameCallback.setName(CoreConstants.GUEST);
233         callbacks.add(nameCallback);
234 
235         PasswordCallback pwdCbk = new PasswordCallback(PASSWORD, false);
236         pwdCbk.setPassword(CoreConstants.GUEST.toCharArray());
237         callbacks.add(pwdCbk);
238 
239         InetAddressCallback address = new InetAddressCallback();
240         final String localIP = "127.0.0.1";
241         address.setHostAdress(localIP);
242         address.setHostName("localhost");
243         callbacks.add(address);
244 
245 
246         LanguageCallback languageCallback = new LanguageCallback();
247         languageCallback.setLocale(Locale.getDefault());
248         callbacks.add(languageCallback);
249 
250         //add HookFormSchemeHandler
251         List<AuthenticationSchemeHandler> authenticationSchemeHandlers = new ArrayList<AuthenticationSchemeHandler>(1);
252         Map<String, String> parameters = new HashMap<String, String>(2);
253         authenticationSchemeHandlers.add(new HookFormSchemeHandler(parameters, authenticationBindings.getAuthenticationBindingsFactory()));
254         return authenticateWithImpersonation(authenticationBindings, authenticationSchemeHandlers, applicationName, callbacks, authenticationScope);
255     }
256 
257 
258 }