View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2015 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.modules;
20  
21  import java.io.IOException;
22  import java.nio.charset.StandardCharsets;
23  import java.util.Map;
24  import java.util.Set;
25  
26  import javax.security.auth.Subject;
27  import javax.security.auth.callback.Callback;
28  import javax.security.auth.callback.CallbackHandler;
29  import javax.security.auth.callback.UnsupportedCallbackException;
30  import javax.security.auth.message.AuthException;
31  import javax.security.auth.message.AuthStatus;
32  import javax.security.auth.message.MessageInfo;
33  import javax.security.auth.message.MessagePolicy;
34  import javax.security.auth.message.callback.CallerPrincipalCallback;
35  import javax.security.auth.message.callback.GroupPrincipalCallback;
36  import javax.security.auth.message.config.ServerAuthContext;
37  import javax.security.auth.message.module.ServerAuthModule;
38  import javax.servlet.http.HttpServletRequest;
39  import javax.servlet.http.HttpServletResponse;
40  
41  import org.eclipse.jetty.security.authentication.LoginCallbackImpl;
42  import org.eclipse.jetty.security.jaspi.JaspiMessageInfo;
43  import org.eclipse.jetty.security.jaspi.callback.CredentialValidationCallback;
44  import org.eclipse.jetty.util.B64Code;
45  import org.eclipse.jetty.util.security.Credential;
46  import org.eclipse.jetty.util.security.Password;
47  
48  public class BaseAuthModule implements ServerAuthModule, ServerAuthContext
49  {
50      private static final Class[] SUPPORTED_MESSAGE_TYPES = new Class[] { HttpServletRequest.class, HttpServletResponse.class };
51  
52      protected static final String LOGIN_SERVICE_KEY = "org.eclipse.jetty.security.jaspi.modules.LoginService";
53  
54      protected CallbackHandler callbackHandler;
55  
56      public Class[] getSupportedMessageTypes()
57      {
58          return SUPPORTED_MESSAGE_TYPES;
59      }
60  
61      public BaseAuthModule()
62      {
63      }
64  
65      public BaseAuthModule(CallbackHandler callbackHandler)
66      {
67          this.callbackHandler = callbackHandler;
68      }
69  
70      public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, CallbackHandler handler, Map options) throws AuthException
71      {
72          this.callbackHandler = handler;
73      }
74  
75      public void cleanSubject(MessageInfo messageInfo, Subject subject) throws AuthException
76      {
77          // TODO apparently we either get the LoginCallback or the LoginService
78          // but not both :-(
79          // Set<LoginCallback> loginCallbacks =
80          // subject.getPrivateCredentials(LoginCallback.class);
81          // if (!loginCallbacks.isEmpty()) {
82          // LoginCallback loginCallback = loginCallbacks.iterator().next();
83          // }
84          // try {
85          // loginService.logout(subject);
86          // } catch (ServerAuthException e) {
87          // throw new AuthException(e.getMessage());
88          // }
89      }
90  
91      public AuthStatus secureResponse(MessageInfo messageInfo, Subject serviceSubject) throws AuthException
92      {
93          // servlets do not need secured responses
94          return AuthStatus.SEND_SUCCESS;
95      }
96  
97      public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) throws AuthException
98      {
99          return AuthStatus.SEND_FAILURE;
100     }
101 
102     /**
103      * @param messageInfo message info to examine for mandatory flag
104      * @return whether authentication is mandatory or optional
105      */
106     protected boolean isMandatory(MessageInfo messageInfo)
107     {
108         String mandatory = (String) messageInfo.getMap().get(JaspiMessageInfo.MANDATORY_KEY);
109         if (mandatory == null) return false;
110         return Boolean.valueOf(mandatory);
111     }
112 
113     protected boolean login(Subject clientSubject, String credentials, 
114                             String authMethod, MessageInfo messageInfo) 
115     throws IOException, UnsupportedCallbackException
116     {
117         credentials = credentials.substring(credentials.indexOf(' ')+1);
118         credentials = B64Code.decode(credentials, StandardCharsets.ISO_8859_1);
119         int i = credentials.indexOf(':');
120         String userName = credentials.substring(0,i);
121         String password = credentials.substring(i+1);
122         return login(clientSubject, userName, new Password(password), authMethod, messageInfo);
123     }
124 
125     protected boolean login(Subject clientSubject, String username, 
126                             Credential credential, String authMethod, 
127                             MessageInfo messageInfo) 
128     throws IOException, UnsupportedCallbackException
129     {
130         CredentialValidationCallback credValidationCallback = new CredentialValidationCallback(clientSubject, username, credential);
131         callbackHandler.handle(new Callback[] { credValidationCallback });
132         if (credValidationCallback.getResult())
133         {
134             Set<LoginCallbackImpl> loginCallbacks = clientSubject.getPrivateCredentials(LoginCallbackImpl.class);
135             if (!loginCallbacks.isEmpty())
136             {
137                 LoginCallbackImpl loginCallback = loginCallbacks.iterator().next();
138                 CallerPrincipalCallback callerPrincipalCallback = new CallerPrincipalCallback(clientSubject, loginCallback.getUserPrincipal());
139                 GroupPrincipalCallback groupPrincipalCallback = new GroupPrincipalCallback(clientSubject, loginCallback.getRoles());
140                 callbackHandler.handle(new Callback[] { callerPrincipalCallback, groupPrincipalCallback });
141             }
142             messageInfo.getMap().put(JaspiMessageInfo.AUTH_METHOD_KEY, authMethod);
143         }
144         return credValidationCallback.getResult();
145 
146     }
147 }