View Javadoc

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