1/*2 * Licensed to the Apache Software Foundation (ASF) under one or more3 * contributor license agreements. See the NOTICE file distributed with4 * this work for additional information regarding copyright ownership.5 * The ASF licenses this file to You under the Apache License, Version 2.06 * (the "License"); you may not use this file except in compliance with7 * the License. You may obtain a copy of the License at8 * 9 * http://www.apache.org/licenses/LICENSE-2.010 * 11 * Unless required by applicable law or agreed to in writing, software12 * distributed under the License is distributed on an "AS IS" BASIS,13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.14 * See the License for the specific language governing permissions and15 * limitations under the License.16 */17packageorg.apache.jetspeed.security.impl.ntlm;
1819import java.security.Principal;
20import java.util.HashSet;
21import java.util.Set;
2223import javax.security.auth.Subject;
2425import org.apache.commons.lang.StringUtils;
26import org.apache.jetspeed.administration.PortalAuthenticationConfiguration;
27import org.apache.jetspeed.pipeline.PipelineException;
28import org.apache.jetspeed.request.RequestContext;
29import org.apache.jetspeed.security.SecurityException;
30import org.apache.jetspeed.security.SecurityHelper;
31import org.apache.jetspeed.security.User;
32import org.apache.jetspeed.security.UserManager;
33import org.apache.jetspeed.security.UserPrincipal;
34import org.apache.jetspeed.security.impl.AbstractSecurityValve;
35import org.apache.jetspeed.security.impl.UserPrincipalImpl;
36import org.apache.jetspeed.statistics.PortalStatistics;
37/***38 * NTLMSecurityValve provides Subject creation based on the39 * NTLM provided request.getRemoteUser() user name. When request.getRemoteUser() holds40 * a valid value, then this user is authorized. Otherwise the username is retrieved41 * from the Principal name in the request. In this way you can use NTLM authentication, with42 * a fallback authentication method in case the user is not properly authenticated / authorized using43 * NTLM. 44 * 45 * There are basically three authentication scenarios:46 * <ol>47 * <li>48 * <p><b>The user is successfully authenticated and authorized by Ntml authentication</b></p>49 * <p>A Subject is created, with Principal derived from the remoteUser value from Ntlm authentication</p>50 * </li>51 * <li> 52 * <p><b>The user is not authenticated by Ntlm, or the authenticated (can be NTLM or any other method) user cannot be authorized by Jetspeed.</b></p>53 * <p>An anonymous Subject is created. The user can then be redirected to a login page for example.</p>54 * </li>55 * <li> 56 * <p><b>The user is authenticated by a (non-NTLM) authentication method, e.g. container-based form authentication.</b></p>57 * <p>58 * A subject is created based on the Principal name in the request.59 * </p>60 * </li>61 * </ol>62 * @author <a href="mailto:taylor@apache.org">David Sean Taylor </a>63 * @author <a href="mailto:rwatler@finali.com">Randy Walter </a>64 * @author <a href="mailto:weaver@apache.org">Scott T. Weaver</a>65 * @author <a href="mailto:d.dam@hippo.nl">Dennis Dam</a>66 * @version $Id$67 */68publicclassNtlmSecurityValveextendsAbstractSecurityValve69 {
70private UserManager userMgr;
71private PortalStatistics statistics;
72private String networkDomain;
73privateboolean ntlmAuthRequired;
74privateboolean omitDomain;
757677/***78 * @param userMgr A UserManager79 * @param statistics Portal Statistics80 * @param networkDomain The network domain is used in combination with the <code>omitDomain</code> flag. 81 * @param omitDomain If <code>true</code>, then the network domain is stripped from the remoteUser name.82 * @param ntlmAuthRequired if <code>true</code>, then an exception is thrown when there is no valid remoteUser,83 * or the remoteUser cannot be authorized.84 * 85 */86publicNtlmSecurityValve(UserManager userMgr, String networkDomain, boolean omitDomain, boolean ntlmAuthRequired,
87 PortalStatistics statistics, PortalAuthenticationConfiguration authenticationConfiguration)
88 {
89this.userMgr = userMgr;
90this.statistics = statistics;
91this.networkDomain = networkDomain;
92this.ntlmAuthRequired = ntlmAuthRequired;
93this.omitDomain = omitDomain;
94this.authenticationConfiguration = authenticationConfiguration;
95 }
9697publicNtlmSecurityValve(UserManager userMgr, String networkDomain, boolean omitDomain, boolean ntlmAuthRequired, PortalStatistics statistics)
98 {
99this(userMgr, networkDomain, omitDomain, ntlmAuthRequired, statistics, null);
100 }
101102publicNtlmSecurityValve(UserManager userMgr, String networkDomain, boolean omitDomain, boolean ntlmAuthRequired)
103 {
104this(userMgr, networkDomain, omitDomain, ntlmAuthRequired, null);
105 }
106107public String toString()
108 {
109return"NtlmSecurityValve";
110 }
111112protected Principal getUserPrincipal(RequestContext context) throws Exception
113 {
114 Subject subject = getSubjectFromSession(context);
115if (subject != null)
116 {
117return SecurityHelper.getPrincipal(subject, UserPrincipal.class);
118 }
119// otherwise return anonymous principal120returnnew UserPrincipalImpl(userMgr.getAnonymousUser());
121 }
122123protected Subject getSubject(RequestContext context) throws Exception
124 {
125 Subject subject = getSubjectFromSession(context);
126// Get remote user name set by web container127 String userName = context.getRequest().getRemoteUser();
128if ( userName == null )
129 {
130if (ntlmAuthRequired){
131thrownew PipelineException("Authorization failed.");
132 } elseif (context.getRequest().getUserPrincipal() != null){
133 userName = context.getRequest().getUserPrincipal().getName();
134 }
135 } else {
136if (omitDomain && networkDomain != null){
137 userName = StringUtils.stripStart( userName , networkDomain+"//");
138 }
139 }
140141// check whether principal name stored in session subject equals the remote user name passed by the web container142if (subject != null)
143 {
144 Principal subjectUserPrincipal = SecurityHelper.getPrincipal(subject, UserPrincipal.class);
145if ((subjectUserPrincipal == null) || !subjectUserPrincipal.getName().equals(userName))
146 {
147 subject = null;
148 }
149 }
150if ( subject == null ){
151if (userName != null){
152try153 {
154 User user = userMgr.getUser(userName);
155if ( user != null )
156 {
157 subject = user.getSubject();
158 }
159 } catch (SecurityException sex)
160 {
161 subject = null;
162 }
163164if (subject == null && this.ntlmAuthRequired){
165thrownew PipelineException("Authorization failed for user '"+userName+"'.");
166 }
167 }
168if (subject == null){
169// create anonymous user170 Principal userPrincipal = getUserPrincipal(context);
171 Set principals = new HashSet();
172 principals.add(userPrincipal);
173 subject = new Subject(true, principals, new HashSet(), new HashSet());
174 }
175176// create a new statistics *user* session177if (statistics != null)
178 {
179 statistics.logUserLogin(context, 0);
180 }
181// put IP address in session for logout182 context.setSessionAttribute(IP_ADDRESS, context.getRequest().getRemoteAddr());
183 }
184185return subject;
186 }
187 }