View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.security.jaspi;
20  
21  import java.security.Principal;
22  import java.util.Map;
23  import java.util.Set;
24  
25  import javax.security.auth.Subject;
26  import javax.security.auth.message.AuthException;
27  import javax.security.auth.message.AuthStatus;
28  import javax.security.auth.message.callback.CallerPrincipalCallback;
29  import javax.security.auth.message.callback.GroupPrincipalCallback;
30  import javax.security.auth.message.config.ServerAuthConfig;
31  import javax.security.auth.message.config.ServerAuthContext;
32  import javax.servlet.ServletRequest;
33  import javax.servlet.ServletResponse;
34  import javax.servlet.http.HttpServletRequest;
35  import javax.servlet.http.HttpSession;
36  
37  import org.eclipse.jetty.security.IdentityService;
38  import org.eclipse.jetty.security.ServerAuthException;
39  import org.eclipse.jetty.security.UserAuthentication;
40  import org.eclipse.jetty.security.authentication.DeferredAuthentication;
41  import org.eclipse.jetty.security.authentication.LoginAuthenticator;
42  import org.eclipse.jetty.security.authentication.SessionAuthentication;
43  import org.eclipse.jetty.server.Authentication;
44  import org.eclipse.jetty.server.Authentication.User;
45  import org.eclipse.jetty.server.UserIdentity;
46  import org.eclipse.jetty.util.log.Log;
47  import org.eclipse.jetty.util.log.Logger;
48  
49  /**
50   * @version $Rev: 4793 $ $Date: 2009-03-19 00:00:01 +0100 (Thu, 19 Mar 2009) $
51   */
52  public class JaspiAuthenticator extends LoginAuthenticator
53  {
54      private static final Logger LOG = Log.getLogger(JaspiAuthenticator.class.getName());
55      
56      private final ServerAuthConfig _authConfig;
57  
58      private final Map _authProperties;
59  
60      private final ServletCallbackHandler _callbackHandler;
61  
62      private final Subject _serviceSubject;
63  
64      private final boolean _allowLazyAuthentication;
65  
66      private final IdentityService _identityService;
67  
68   
69  
70      public JaspiAuthenticator(ServerAuthConfig authConfig, Map authProperties, ServletCallbackHandler callbackHandler, Subject serviceSubject,
71                                boolean allowLazyAuthentication, IdentityService identityService)
72      {
73          // TODO maybe pass this in via setConfiguration ?
74          if (callbackHandler == null) throw new NullPointerException("No CallbackHandler");
75          if (authConfig == null) throw new NullPointerException("No AuthConfig");
76          this._authConfig = authConfig;
77          this._authProperties = authProperties;
78          this._callbackHandler = callbackHandler;
79          this._serviceSubject = serviceSubject;
80          this._allowLazyAuthentication = allowLazyAuthentication;
81          this._identityService = identityService;
82      }
83  
84      public void setConfiguration(AuthConfiguration configuration)
85      {
86          super.setConfiguration(configuration);
87      }
88  
89      public String getAuthMethod()
90      {
91          return "JASPI";
92      }
93  
94      public Authentication validateRequest(ServletRequest request, ServletResponse response, boolean mandatory) throws ServerAuthException
95      {
96          JaspiMessageInfo info = new JaspiMessageInfo(request, response, mandatory);
97          request.setAttribute("org.eclipse.jetty.security.jaspi.info", info);
98  
99          Authentication a = validateRequest(info);
100         
101         //if its not mandatory to authenticate, and the authenticator returned UNAUTHENTICATED, we treat it as authentication deferred
102         if (_allowLazyAuthentication && !info.isAuthMandatory() && a == Authentication.UNAUTHENTICATED)
103             a = new DeferredAuthentication(this);
104         return a;
105     }
106 
107     // most likely validatedUser is not needed here.
108     public boolean secureResponse(ServletRequest req, ServletResponse res, boolean mandatory, User validatedUser) throws ServerAuthException
109     {
110         JaspiMessageInfo info = (JaspiMessageInfo) req.getAttribute("org.eclipse.jetty.security.jaspi.info");
111         if (info == null) throw new NullPointerException("MessageInfo from request missing: " + req);
112         return secureResponse(info, validatedUser);
113     }
114 
115 
116     /** 
117      * @see org.eclipse.jetty.security.authentication.LoginAuthenticator#login(java.lang.String, java.lang.Object, javax.servlet.ServletRequest)
118      */
119     @Override
120     public UserIdentity login(String username, Object password, ServletRequest request)
121     { 
122         UserIdentity user = _loginService.login(username, password);
123         if (user != null)
124         {
125             renewSession((HttpServletRequest)request, null);
126             HttpSession session = ((HttpServletRequest)request).getSession(true);
127             if (session != null)
128             {
129                 SessionAuthentication sessionAuth = new SessionAuthentication(getAuthMethod(), user, password);
130                 session.setAttribute(SessionAuthentication.__J_AUTHENTICATED, sessionAuth);
131             }
132         }
133         return user;
134     }
135 
136     
137 
138     public Authentication validateRequest(JaspiMessageInfo messageInfo) throws ServerAuthException
139     {
140         try
141         {
142             String authContextId = _authConfig.getAuthContextID(messageInfo);
143             ServerAuthContext authContext = _authConfig.getAuthContext(authContextId, _serviceSubject, _authProperties);
144             Subject clientSubject = new Subject();
145 
146             AuthStatus authStatus = authContext.validateRequest(messageInfo, clientSubject, _serviceSubject);
147 
148             if (authStatus == AuthStatus.SEND_CONTINUE) return Authentication.SEND_CONTINUE;
149             if (authStatus == AuthStatus.SEND_FAILURE) return Authentication.SEND_FAILURE;
150 
151             if (authStatus == AuthStatus.SUCCESS)
152             {
153                 Set<UserIdentity> ids = clientSubject.getPrivateCredentials(UserIdentity.class);
154                 UserIdentity userIdentity;
155                 if (ids.size() > 0)
156                 {
157                     userIdentity = ids.iterator().next();
158                 }
159                 else
160                 {
161                     CallerPrincipalCallback principalCallback = _callbackHandler.getThreadCallerPrincipalCallback();
162                     if (principalCallback == null) { return Authentication.UNAUTHENTICATED; }
163                     Principal principal = principalCallback.getPrincipal();
164                     if (principal == null)
165                     {
166                         String principalName = principalCallback.getName();
167                         Set<Principal> principals = principalCallback.getSubject().getPrincipals();
168                         for (Principal p : principals)
169                         {
170                             if (p.getName().equals(principalName))
171                             {
172                                 principal = p;
173                                 break;
174                             }
175                         }
176                         if (principal == null) { return Authentication.UNAUTHENTICATED; }
177                     }
178                     GroupPrincipalCallback groupPrincipalCallback = _callbackHandler.getThreadGroupPrincipalCallback();
179                     String[] groups = groupPrincipalCallback == null ? null : groupPrincipalCallback.getGroups();
180                     userIdentity = _identityService.newUserIdentity(clientSubject, principal, groups);
181                 }
182                 
183                 HttpSession session = ((HttpServletRequest)messageInfo.getRequestMessage()).getSession(false);
184                 Authentication cached = (session == null?null:(SessionAuthentication)session.getAttribute(SessionAuthentication.__J_AUTHENTICATED));
185                 if (cached != null)
186                     return cached;
187                 
188                 return new UserAuthentication(getAuthMethod(), userIdentity);
189             }
190             if (authStatus == AuthStatus.SEND_SUCCESS)
191             {
192                 // we are processing a message in a secureResponse dialog.
193                 return Authentication.SEND_SUCCESS;
194             }
195             // should not happen
196             throw new NullPointerException("No AuthStatus returned");
197         }
198         catch (AuthException e)
199         {
200             throw new ServerAuthException(e);
201         }
202     }
203 
204     public boolean secureResponse(JaspiMessageInfo messageInfo, Authentication validatedUser) throws ServerAuthException
205     {
206         try
207         {
208             String authContextId = _authConfig.getAuthContextID(messageInfo);
209             ServerAuthContext authContext = _authConfig.getAuthContext(authContextId, _serviceSubject, _authProperties);
210             // TODO
211             // authContext.cleanSubject(messageInfo,validatedUser.getUserIdentity().getSubject());
212             AuthStatus status = authContext.secureResponse(messageInfo, _serviceSubject);
213             return (AuthStatus.SEND_SUCCESS.equals(status));
214         }
215         catch (AuthException e)
216         {
217             throw new ServerAuthException(e);
218         }
219     }
220 
221 }