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  
35  import org.eclipse.jetty.security.Authenticator;
36  import org.eclipse.jetty.security.IdentityService;
37  import org.eclipse.jetty.security.ServerAuthException;
38  import org.eclipse.jetty.security.UserAuthentication;
39  import org.eclipse.jetty.security.authentication.DeferredAuthentication;
40  import org.eclipse.jetty.security.authentication.LoginAuthenticator;
41  import org.eclipse.jetty.server.Authentication;
42  import org.eclipse.jetty.server.UserIdentity;
43  import org.eclipse.jetty.server.Authentication.User;
44  
45  /**
46   * @version $Rev: 4793 $ $Date: 2009-03-19 00:00:01 +0100 (Thu, 19 Mar 2009) $
47   */
48  public class JaspiAuthenticator extends LoginAuthenticator
49  {
50      private final ServerAuthConfig _authConfig;
51  
52      private final Map _authProperties;
53  
54      private final ServletCallbackHandler _callbackHandler;
55  
56      private final Subject _serviceSubject;
57  
58      private final boolean _allowLazyAuthentication;
59  
60      private final IdentityService _identityService;
61  
62   
63  
64      public JaspiAuthenticator(ServerAuthConfig authConfig, Map authProperties, ServletCallbackHandler callbackHandler, Subject serviceSubject,
65                                boolean allowLazyAuthentication, IdentityService identityService)
66      {
67          // TODO maybe pass this in via setConfiguration ?
68          if (callbackHandler == null) throw new NullPointerException("No CallbackHandler");
69          if (authConfig == null) throw new NullPointerException("No AuthConfig");
70          this._authConfig = authConfig;
71          this._authProperties = authProperties;
72          this._callbackHandler = callbackHandler;
73          this._serviceSubject = serviceSubject;
74          this._allowLazyAuthentication = allowLazyAuthentication;
75          this._identityService = identityService;
76      }
77  
78      public void setConfiguration(AuthConfiguration configuration)
79      {
80          super.setConfiguration(configuration);
81      }
82  
83      public String getAuthMethod()
84      {
85          return "JASPI";
86      }
87  
88      public Authentication validateRequest(ServletRequest request, ServletResponse response, boolean mandatory) throws ServerAuthException
89      {
90          JaspiMessageInfo info = new JaspiMessageInfo(request, response, mandatory);
91          request.setAttribute("org.eclipse.jetty.security.jaspi.info", info);
92  
93          Authentication a = validateRequest(info);
94          
95          //if its not mandatory to authenticate, and the authenticator returned UNAUTHENTICATED, we treat it as authentication deferred
96          if (_allowLazyAuthentication && !info.isAuthMandatory() && a == Authentication.UNAUTHENTICATED)
97              a = new DeferredAuthentication(this);
98          return a;
99      }
100 
101     // most likely validatedUser is not needed here.
102     public boolean secureResponse(ServletRequest req, ServletResponse res, boolean mandatory, User validatedUser) throws ServerAuthException
103     {
104         JaspiMessageInfo info = (JaspiMessageInfo) req.getAttribute("org.eclipse.jetty.security.jaspi.info");
105         if (info == null) throw new NullPointerException("MessageInfo from request missing: " + req);
106         return secureResponse(info, validatedUser);
107     }
108 
109 
110     public Authentication validateRequest(JaspiMessageInfo messageInfo) throws ServerAuthException
111     {
112         try
113         {
114             String authContextId = _authConfig.getAuthContextID(messageInfo);
115             ServerAuthContext authContext = _authConfig.getAuthContext(authContextId, _serviceSubject, _authProperties);
116             Subject clientSubject = new Subject();
117 
118             AuthStatus authStatus = authContext.validateRequest(messageInfo, clientSubject, _serviceSubject);
119 
120             if (authStatus == AuthStatus.SEND_CONTINUE) return Authentication.SEND_CONTINUE;
121             if (authStatus == AuthStatus.SEND_FAILURE) return Authentication.SEND_FAILURE;
122 
123             if (authStatus == AuthStatus.SUCCESS)
124             {
125                 Set<UserIdentity> ids = clientSubject.getPrivateCredentials(UserIdentity.class);
126                 UserIdentity userIdentity;
127                 if (ids.size() > 0)
128                 {
129                     userIdentity = ids.iterator().next();
130                 }
131                 else
132                 {
133                     CallerPrincipalCallback principalCallback = _callbackHandler.getThreadCallerPrincipalCallback();
134                     if (principalCallback == null) { return Authentication.UNAUTHENTICATED; }
135                     Principal principal = principalCallback.getPrincipal();
136                     if (principal == null)
137                     {
138                         String principalName = principalCallback.getName();
139                         Set<Principal> principals = principalCallback.getSubject().getPrincipals();
140                         for (Principal p : principals)
141                         {
142                             if (p.getName().equals(principalName))
143                             {
144                                 principal = p;
145                                 break;
146                             }
147                         }
148                         if (principal == null) { return Authentication.UNAUTHENTICATED; }
149                     }
150                     GroupPrincipalCallback groupPrincipalCallback = _callbackHandler.getThreadGroupPrincipalCallback();
151                     String[] groups = groupPrincipalCallback == null ? null : groupPrincipalCallback.getGroups();
152                     userIdentity = _identityService.newUserIdentity(clientSubject, principal, groups);
153                 }
154                 return new UserAuthentication(getAuthMethod(), userIdentity);
155             }
156             if (authStatus == AuthStatus.SEND_SUCCESS)
157             {
158                 // we are processing a message in a secureResponse dialog.
159                 return Authentication.SEND_SUCCESS;
160             }
161             // should not happen
162             throw new NullPointerException("No AuthStatus returned");
163         }
164         catch (AuthException e)
165         {
166             throw new ServerAuthException(e);
167         }
168     }
169 
170     public boolean secureResponse(JaspiMessageInfo messageInfo, Authentication validatedUser) throws ServerAuthException
171     {
172         try
173         {
174             String authContextId = _authConfig.getAuthContextID(messageInfo);
175             ServerAuthContext authContext = _authConfig.getAuthContext(authContextId, _serviceSubject, _authProperties);
176             // TODO
177             // authContext.cleanSubject(messageInfo,validatedUser.getUserIdentity().getSubject());
178             AuthStatus status = authContext.secureResponse(messageInfo, _serviceSubject);
179             return (AuthStatus.SEND_SUCCESS.equals(status));
180         }
181         catch (AuthException e)
182         {
183             throw new ServerAuthException(e);
184         }
185     }
186 
187 }