KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > jetspeed > modules > actions > NTLMSessionValidator


1 /*
2  * Copyright 2000-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.jetspeed.modules.actions;
17
18 // JDK stuff
19
import java.util.Locale JavaDoc;
20 import javax.servlet.http.HttpServletRequest JavaDoc;
21 import javax.servlet.http.HttpServletResponse JavaDoc;
22
23 // Turbine APIs
24
import org.apache.turbine.util.RunData;
25 import org.apache.turbine.services.resources.TurbineResources;
26 import org.apache.turbine.services.localization.LocalizationService;
27
28 // Jetspeed APIs
29
import org.apache.jetspeed.om.security.JetspeedUser;
30 import org.apache.jetspeed.services.JetspeedSecurity;
31 import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
32 import org.apache.jetspeed.services.logging.JetspeedLogger;
33 import org.apache.jetspeed.services.security.LoginException;
34 import org.apache.jetspeed.services.rundata.JetspeedRunData;
35 import org.apache.jetspeed.util.ServiceUtil;
36 import org.apache.jetspeed.services.customlocalization.CustomLocalizationService;
37 import org.apache.jetspeed.services.security.UnknownUserException;
38 import org.apache.jetspeed.services.security.JetspeedSecurityCache;
39
40 /**
41  * Just like org.apache.turbine.modules.actions.sessionvalidator.TemplateSessionValidator except:
42  * <ul>
43  * <li> it doesn't check the session_access_counter
44  * <li> it automatically logs the user in based on currently authenticated nt user
45  * <li> expects a JetspeedRunData object and put there the additionnal jetspeed properties
46  * </ul>
47  * <B>Usage of this session validator is limited to Windows NT/2000 and MS Internet Explorer.</B>
48  * <P>
49  * To activate this session validator, set <CODE>action.sessionvalidator</CODE> in tr.props to
50  * <code>NTLMSessionValidator</code>.
51  * </P>
52  * <P>
53  * When this session validator is active, the following algorithm is used to display appropriate psml:
54  * <pre>
55  * Check authentication status
56  * If user is not authenticated to machine running the portal
57  * Pop the standard login box
58  * If user passes authentication
59  * Attempt to retrieve matching user profile
60  * If matching profile found
61  * Render the profile
62  * Else
63  * Retrieve and render anonymous profile
64  * End
65  * Else If authentication fails
66  * Keep prompting for login information
67  * Else If the user cancels the login box
68  * Retrieve and render anonymous profile
69  * End
70  * Else
71  * Attempt to retrieve matching user profile
72  * If matching profile found
73  * Render the profile
74  * Else
75  * Retrieve and render anonymous profile
76  * End
77  * End
78  * </pre>
79  * </P>
80  * <P>
81  * Optionally, certain characters may be removed from the username before it's passed to the
82  * JetspeedSecurity. These characters may be specified by setting <CODE>NTLMSessionValidator.chars.to.remove</CODE>
83  * property. For example, if invalid characters list is '#@$', username '#user1' will be returned as 'user1'.
84  * </P>
85  *
86  * @author <a HREF="mailto:morciuch@apache.org">Mark Orciuch</a>
87  * @version $Id: NTLMSessionValidator.java,v 1.6 2004/02/23 02:59:06 jford Exp $
88  * @see org.apache.turbine.modules.actions.sessionvalidator.TemplateSessionValidator
89  * @see http://www.innovation.ch/java/ntlm.html
90  * @since 1.4b5
91  */

92 public class NTLMSessionValidator extends TemplateSessionValidator
93 {
94
95     private static final String JavaDoc INVALID_CHARS_KEY = "NTLMSessionValidator.chars.to.remove";
96
97     private String JavaDoc invalidChars = org.apache.jetspeed.services.resources.JetspeedResources.getString(INVALID_CHARS_KEY, null);
98
99     private static final byte z = 0;
100     private static final byte[] msg1 = {(byte) 'N', (byte) 'T', (byte) 'L', (byte) 'M', (byte) 'S', (byte) 'S', (byte) 'P',
101         z, (byte) 2, z, z, z, z, z, z, z, (byte) 40, z, z, z,
102         (byte) 1, (byte) 130, z, z, z, (byte) 2, (byte) 2,
103         (byte) 2, z, z, z, z, z, z, z, z, z, z, z, z};
104     private static final String JavaDoc encodedMsg1 = "NTLM " + new sun.misc.BASE64Encoder().encodeBuffer(msg1).trim();
105
106     /**
107      * Static initialization of the logger for this class
108      */

109     private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(NTLMSessionValidator.class.getName());
110     
111     /**
112      * Execute the action.
113      *
114      * @param data Turbine information.
115      * @exception Exception, a generic exception.
116      */

117     public void doPerform(RunData data) throws Exception JavaDoc
118     {
119         //first, invoke our superclass action to make sure
120
//we follow Turbine evolutions
121
//FIXME: if the user is not found (this can happen, for instance,
122
// if the anonymous user is not in the DB), it throws a terrible exception
123
// in the user's face
124
super.doPerform(data);
125
126         JetspeedUser user = (JetspeedUser) data.getUser();
127         
128         // get remote user from ntlm
129
String JavaDoc userName = this.getRemoteUser(data);
130
131         if ((user == null || !user.hasLoggedIn()))
132         {
133             if (userName != null && userName.length() > 0)
134             {
135                 byte[] temp = userName.getBytes();
136                 StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
137                 for (int i = 0; i < temp.length; i++)
138                 {
139                     if (temp[i] != 0)
140                     {
141                         if (invalidChars == null || invalidChars.indexOf((int) temp[i]) < 0)
142                         {
143                             buffer.append((char) temp[i]);
144                         }
145                     }
146                 }
147                 userName = buffer.toString();
148                 try
149                 {
150                     user = JetspeedSecurity.getUser(userName);
151                     data.setUser(user);
152                     user.setHasLoggedIn(new Boolean JavaDoc(true));
153                     user.updateLastLogin();
154                     data.save();
155                     if (JetspeedSecurityCache.getAcl(userName) == null)
156                     {
157                         JetspeedSecurityCache.load(userName);
158                     }
159                     logger.info("NTLMSessionValidator: automatic login using [" + userName + "]");
160                 }
161                 catch (LoginException noSuchUser)
162                 {
163                     //user not found - ignore it - they will not be logged in automatically
164
}
165                 catch (UnknownUserException unknownUser)
166                 {
167                     //user not found - ignore it - they will not be logged in automatically
168
if (logger.isWarnEnabled())
169                     {
170                         logger.warn("NTLMSessionValidator: username [" + userName + "] does not exist or authentication failed, "
171                                  + "redirecting to anon profile");
172                     }
173                 }
174             }
175         }
176
177         // now, define Jetspeed specific properties, using the customized
178
// RunData properties
179
JetspeedRunData jdata = null;
180
181         try
182         {
183             jdata = (JetspeedRunData) data;
184         }
185         catch (ClassCastException JavaDoc e)
186         {
187             logger.error("The RunData object does not implement the expected interface, "
188                       + "please verify the RunData factory settings");
189             return;
190         }
191         String JavaDoc language = (String JavaDoc) data.getRequest().getParameter("js_language");
192
193         if (null != language)
194         {
195             user.setPerm("language", language);
196         }
197
198         // Get the locale store it in the user object
199
CustomLocalizationService locService =
200             (CustomLocalizationService) ServiceUtil.getServiceByName(LocalizationService.SERVICE_NAME);
201         Locale JavaDoc locale = locService.getLocale(data);
202         if (locale == null)
203         {
204             locale = new Locale JavaDoc(TurbineResources.getString("locale.default.language", "en"),
205                                 TurbineResources.getString("locale.default.country", "US"));
206         }
207
208         data.getUser().setTemp("locale", locale);
209
210         // if a portlet is referenced in the parameters request, store it
211
// in the RunData object
212
String JavaDoc paramPortlet = jdata.getParameters().getString("js_peid");
213         if (paramPortlet != null && paramPortlet.length() > 0)
214         {
215             jdata.setJs_peid(paramPortlet);
216         }
217
218     }
219
220     /**
221      * This session validator does not require a new session for each request
222      *
223      * @param data
224      * @return
225      */

226     public boolean requiresNewSession(RunData data)
227     {
228         return false;
229     }
230
231     /**
232      * Extracts user name from http headers
233      *
234      * @param data
235      * @return
236      * @exception Exception
237      */

238     private String JavaDoc getRemoteUser(RunData data) throws Exception JavaDoc
239     {
240         HttpServletRequest JavaDoc request = data.getRequest();
241         HttpServletResponse JavaDoc response = data.getResponse();
242
243         if (data.getUser().hasLoggedIn() && request.getMethod().equalsIgnoreCase("get"))
244         {
245             return data.getUser().getUserName();
246         }
247
248         String JavaDoc auth = request.getHeader("Authorization");
249         if (auth == null)
250         {
251             response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
252             response.setHeader("WWW-Authenticate", "NTLM");
253             response.flushBuffer();
254
255             return null;
256         }
257         if (auth.startsWith("NTLM "))
258         {
259             byte[] msg = new sun.misc.BASE64Decoder().decodeBuffer(auth.substring(5));
260             int off = 0, length, offset;
261             
262             if (msg[8] == 1)
263             {
264                 response.setHeader("WWW-Authenticate", encodedMsg1);
265                 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
266
267                 return null;
268             }
269             else if (msg[8] == 3)
270             {
271                 if (data.getUser().hasLoggedIn())
272                 {
273                     return data.getUser().getUserName();
274                 }
275
276                 off = 30;
277
278                 //length = msg[off + 17] * 256 + msg[off + 16];
279
//offset = msg[off + 19] * 256 + msg[off + 18];
280
//String remoteHost = new String(msg, offset, length);
281

282                 //length = msg[off + 1] * 256 + msg[off];
283
//offset = msg[off + 3] * 256 + msg[off + 2];
284
//String domain = new String(msg, offset, length);
285

286                 length = msg[off + 9] * 256 + msg[off + 8];
287                 offset = msg[off + 11] * 256 + msg[off + 10];
288                 String JavaDoc username = new String JavaDoc(msg, offset, length);
289
290                 return username;
291             }
292
293         }
294
295         return null;
296     }
297 }
298
Popular Tags