You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jetspeed-dev@portals.apache.org by ta...@apache.org on 2007/05/12 00:50:42 UTC
svn commit: r537309 - in /portals/jetspeed-2/trunk:
components/portal/src/java/org/apache/jetspeed/security/impl/ntlm/
xdocs/guides/
Author: taylor
Date: Fri May 11 15:50:41 2007
New Revision: 537309
URL: http://svn.apache.org/viewvc?view=rev&rev=537309
Log:
https://issues.apache.org/jira/browse/JS2-720
NTLM Security Valve + Documentation
contribution from Dennis Dam
Added:
portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/security/impl/ntlm/
portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/security/impl/ntlm/NtlmHttpServletRequestFilter.java
portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/security/impl/ntlm/NtlmHttpServletRequestWrapper.java
portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/security/impl/ntlm/NtlmSecurityValve.java
portals/jetspeed-2/trunk/xdocs/guides/guide-ntlm.xml
Modified:
portals/jetspeed-2/trunk/xdocs/guides/index.xml
Added: portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/security/impl/ntlm/NtlmHttpServletRequestFilter.java
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/security/impl/ntlm/NtlmHttpServletRequestFilter.java?view=auto&rev=537309
==============================================================================
--- portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/security/impl/ntlm/NtlmHttpServletRequestFilter.java (added)
+++ portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/security/impl/ntlm/NtlmHttpServletRequestFilter.java Fri May 11 15:50:41 2007
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jetspeed.security.impl.ntlm;
+
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+/**
+ * <code>NtlmHttpServletRequestFilter</code> can be used in combination with an Ntml authentication filter (jCIFS).
+ * The <code>NtlmHttpServletRequestFilter</code> <b>must</b> be configured after the jCIFS filter in web.xml. The
+ * NtlmHttpServletRequestFilter wraps the jCIFS HttpServletRequest with a <code>NtlmHttpServletRequestWrapper</code>.
+ * This is done to control which principal / remoteUser is returned by the request.
+ * If a fallback authentication method is used (e.g. container-based form authentication) then you must
+ * use the filter param <code>org.apache.jetspeed.security.ntlm.ignoreUrls</code> in web.xml to specify the urls for
+ * which the Ntlm principal / remoteUser should be ignored.
+ *
+ * @see NtlmHttpServletRequestWrapper
+ * @author <a href="mailto:d.dam@hippo.nl">Dennis Dam</a>
+ * @version $Id$
+ */
+public class NtlmHttpServletRequestFilter implements Filter {
+
+ private String ignoreNtlmUrls;
+
+ public void destroy() {
+ }
+
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
+ ServletException {
+ HttpServletRequest req = (HttpServletRequest)request;
+ HttpServletResponse resp = (HttpServletResponse)response;
+ chain.doFilter( new NtlmHttpServletRequestWrapper( req, ignoreNtlmUrls ), resp );
+ }
+
+ public void init(FilterConfig config) throws ServletException {
+ ignoreNtlmUrls = config.getInitParameter("org.apache.jetspeed.security.ntlm.ignoreUrls");
+ }
+
+}
Added: portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/security/impl/ntlm/NtlmHttpServletRequestWrapper.java
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/security/impl/ntlm/NtlmHttpServletRequestWrapper.java?view=auto&rev=537309
==============================================================================
--- portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/security/impl/ntlm/NtlmHttpServletRequestWrapper.java (added)
+++ portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/security/impl/ntlm/NtlmHttpServletRequestWrapper.java Fri May 11 15:50:41 2007
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jetspeed.security.impl.ntlm;
+
+import java.security.Principal;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * NtlmHttpServletRequestWrapper should be used in combination with an Ntml authentication filter (jCIFS).
+ * This filter wraps the original request, setting the principal and remoteUser retrieved by Ntml
+ * authentication with the client. The wrapper Request sets the principal and remoteUser, <i>regardless</i>
+ * of the principal already present in the original request. This HttpServletRequestWrapper returns the principal
+ * from the original request when it's there, and otherwise returns the Ntml principal. When the
+ * the Ntml principal is actually returned can be influenced by a comma-separated list of servlet urls:
+ * only for these urls the Ntlm principal / remoteUser is ignored.
+ * @see NtlmHttpServletRequestFilter
+ * @author <a href="mailto:d.dam@hippo.nl">Dennis Dam</a>
+ * @version $Id$
+ */
+public class NtlmHttpServletRequestWrapper extends HttpServletRequestWrapper {
+ private Principal principal;
+ private String remoteUser;
+
+ public NtlmHttpServletRequestWrapper(HttpServletRequest req, String ignoreNtmlUrls) {
+ super(req);
+ if (req instanceof HttpServletRequestWrapper){
+ String[] urls = ignoreNtmlUrls != null ? StringUtils.split(ignoreNtmlUrls, ',') : new String[]{};
+ String servletUrl = req.getServletPath();
+ Principal reqPrincipal = req.getUserPrincipal();
+ HttpServletRequest originalRequest = (HttpServletRequest)((HttpServletRequestWrapper) req).getRequest();
+ /*
+ * Original request principal has precedence over Ntml authenticated principal. This is needed
+ * in the case that the Ntlm authenticated principal is not authorized by Jetspeed: a fallback login
+ * method can then be used. If Ntml authentication succeeds, then the principal from the
+ * original request will be null.
+ */
+ if (originalRequest.getUserPrincipal() != null){
+ principal = originalRequest.getUserPrincipal();
+ } else
+ /*
+ * If no principal in the original request, take principal from Ntlm authentication, but
+ * only if the current servlet url is not in the ignore list. The last
+ * requirement is necessary when falling back to another authentication method, e.g. container-based
+ * form authentication: these authentication methods might only work if there is no
+ * principal in the request.
+ */
+ if (!ArrayUtils.contains(urls,servletUrl) && reqPrincipal != null && req.getRemoteUser() != null){
+ principal = reqPrincipal;
+ remoteUser = req.getRemoteUser();
+ }
+ } else {
+ principal = super.getUserPrincipal();
+ }
+ }
+
+ public Principal getUserPrincipal() {
+ return principal;
+ }
+
+ public String getRemoteUser() {
+ return remoteUser;
+ }
+
+}
Added: portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/security/impl/ntlm/NtlmSecurityValve.java
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/security/impl/ntlm/NtlmSecurityValve.java?view=auto&rev=537309
==============================================================================
--- portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/security/impl/ntlm/NtlmSecurityValve.java (added)
+++ portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/security/impl/ntlm/NtlmSecurityValve.java Fri May 11 15:50:41 2007
@@ -0,0 +1,178 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jetspeed.security.impl.ntlm;
+
+import java.security.Principal;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.security.auth.Subject;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.jetspeed.pipeline.PipelineException;
+import org.apache.jetspeed.request.RequestContext;
+import org.apache.jetspeed.security.SecurityException;
+import org.apache.jetspeed.security.SecurityHelper;
+import org.apache.jetspeed.security.User;
+import org.apache.jetspeed.security.UserManager;
+import org.apache.jetspeed.security.UserPrincipal;
+import org.apache.jetspeed.security.impl.AbstractSecurityValve;
+import org.apache.jetspeed.security.impl.UserPrincipalImpl;
+import org.apache.jetspeed.statistics.PortalStatistics;
+/**
+ * NTLMSecurityValve provides Subject creation based on the
+ * NTLM provided request.getRemoteUser() user name. When request.getRemoteUser() holds
+ * a valid value, then this user is authorized. Otherwise the username is retrieved
+ * from the Principal name in the request. In this way you can use NTLM authentication, with
+ * a fallback authentication method in case the user is not properly authenticated / authorized using
+ * NTLM.
+ *
+ * There are basically three authentication scenarios:
+ * <ol>
+ * <li>
+ * <p><b>The user is successfully authenticated and authorized by Ntml authentication</b></p>
+ * <p>A Subject is created, with Principal derived from the remoteUser value from Ntlm authentication</p>
+ * </li>
+ * <li>
+ * <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>
+ * <p>An anonymous Subject is created. The user can then be redirected to a login page for example.</p>
+ * </li>
+ * <li>
+ * <p><b>The user is authenticated by a (non-NTLM) authentication method, e.g. container-based form authentication.</b></p>
+ * <p>
+ * A subject is created based on the Principal name in the request.
+ * </p>
+ * </li>
+ * </ol>
+ * @author <a href="mailto:taylor@apache.org">David Sean Taylor </a>
+ * @author <a href="mailto:rwatler@finali.com">Randy Walter </a>
+ * @author <a href="mailto:weaver@apache.org">Scott T. Weaver</a>
+ * @author <a href="mailto:d.dam@hippo.nl">Dennis Dam</a>
+ * @version $Id$
+ */
+public class NtlmSecurityValve extends AbstractSecurityValve
+{
+ private UserManager userMgr;
+ private PortalStatistics statistics;
+ private String networkDomain;
+ private boolean ntlmAuthRequired;
+ private boolean omitDomain;
+
+
+ /**
+ * @param userMgr A UserManager
+ * @param statistics Portal Statistics
+ * @param networkDomain The network domain is used in combination with the <code>omitDomain</code> flag.
+ * @param omitDomain If <code>true</code>, then the network domain is stripped from the remoteUser name.
+ * @param ntlmAuthRequired if <code>true</code>, then an exception is thrown when there is no valid remoteUser,
+ * or the remoteUser cannot be authorized.
+ *
+ */
+ public NtlmSecurityValve(UserManager userMgr, String networkDomain, boolean omitDomain, boolean ntlmAuthRequired, PortalStatistics statistics)
+ {
+ this.userMgr = userMgr;
+ this.statistics = statistics;
+ this.networkDomain = networkDomain;
+ this.ntlmAuthRequired = ntlmAuthRequired;
+ this.omitDomain = omitDomain;
+ }
+
+ public NtlmSecurityValve(UserManager userMgr, String networkDomain, boolean omitDomain, boolean ntlmAuthRequired){
+ this(userMgr, networkDomain, omitDomain, ntlmAuthRequired, null);
+ }
+
+ public String toString()
+ {
+ return "NtlmSecurityValve";
+ }
+
+ protected Principal getUserPrincipal(RequestContext context) throws Exception
+ {
+ Subject subject = getSubjectFromSession(context);
+ if (subject != null)
+ {
+ return SecurityHelper.getPrincipal(subject, UserPrincipal.class);
+ }
+ // otherwise return anonymous principal
+ return new UserPrincipalImpl(userMgr.getAnonymousUser());
+ }
+
+ protected Subject getSubject(RequestContext context) throws Exception
+ {
+ Subject subject = getSubjectFromSession(context);
+ // Get remote user name set by web container
+ String userName = context.getRequest().getRemoteUser();
+ if ( userName == null )
+ {
+ if (ntlmAuthRequired){
+ throw new PipelineException("Authorization failed.");
+ } else if (context.getRequest().getUserPrincipal() != null){
+ userName = context.getRequest().getUserPrincipal().getName();
+ }
+ } else {
+ if (omitDomain && networkDomain != null){
+ userName = StringUtils.stripStart( userName , networkDomain+"\\");
+ }
+ }
+
+ // check whether principal name stored in session subject equals the remote user name passed by the web container
+ if (subject != null)
+ {
+ Principal subjectUserPrincipal = SecurityHelper.getPrincipal(subject, UserPrincipal.class);
+ if ((subjectUserPrincipal == null) || !subjectUserPrincipal.getName().equals(userName))
+ {
+ subject = null;
+ }
+ }
+ if ( subject == null ){
+ if (userName != null){
+ try
+ {
+ User user = userMgr.getUser(userName);
+ if ( user != null )
+ {
+ subject = user.getSubject();
+ }
+ } catch (SecurityException sex)
+ {
+ subject = null;
+ }
+
+ if (subject == null && this.ntlmAuthRequired){
+ throw new PipelineException("Authorization failed for user '"+userName+"'.");
+ }
+ }
+ if (subject == null){
+ // create anonymous user
+ Principal userPrincipal = getUserPrincipal(context);
+ Set principals = new HashSet();
+ principals.add(userPrincipal);
+ subject = new Subject(true, principals, new HashSet(), new HashSet());
+ }
+
+ // create a new statistics *user* session
+ if (statistics != null)
+ {
+ statistics.logUserLogin(context, 0);
+ }
+ // put IP address in session for logout
+ context.setSessionAttribute(IP_ADDRESS, context.getRequest().getRemoteAddr());
+ }
+
+ return subject;
+ }
+}
Added: portals/jetspeed-2/trunk/xdocs/guides/guide-ntlm.xml
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/trunk/xdocs/guides/guide-ntlm.xml?view=auto&rev=537309
==============================================================================
--- portals/jetspeed-2/trunk/xdocs/guides/guide-ntlm.xml (added)
+++ portals/jetspeed-2/trunk/xdocs/guides/guide-ntlm.xml Fri May 11 15:50:41 2007
@@ -0,0 +1,106 @@
+<?xml version="1.0"?>
+<!--
+ Copyright 2004 The Apache Software Foundation
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<document>
+ <properties>
+ <title>Guide to using NTLM Authentication</title>
+ <subtitle>How to configure NTLM authentication with an optional fallback authentication method.</subtitle>
+ <authors>
+ <person name="Dennis Dam" email="d.dam@hippo.nl" />
+ </authors>
+ </properties>
+ <body>
+ <section name="NTLM Authentication in Jetspeed">
+ <p>
+ NTLM Authentication can be used for Single Sign On (SSO) from a Windows client/browser. A nice explanation about NTLM can be found <a href="http://jcifs.samba.org/src/docs/ntlmhttpauth.html">here</a>.
+ Jetspeed-2 supports NTLM Authentication based on the <a href="http://jcifs.samba.org">jCIFS</a> Servlet filter. With the approach described below
+ you can use NTLM Authentication with an optional fallback to the default active authentication and as such this solution can be used as a drop-in replacement.
+ A typical application for a fallback login method would be when users log on to an intranet from a different domain: these users can
+ be redirected to a login screen.<br/>
+ The solution below can also be used as a replacement for the default Security Valve:
+ if you don't configure the filters, then Jetspeed's default authorization will be applied.
+ </p>
+ </section>
+ <section name="Configuring NTLM Authentication">
+ <p>
+ Jetspeed-2 security configuration is explained
+ <a href="guide-security.html">
+ here
+ </a>
+ .
+ </p>
+ <subsection name="Configuring NTLM servlet filters">
+ <p>
+ The first step is to configure jCIFS NTLM HTTP Authentication, which is explained <a href="http://jcifs.samba.org/">here</a>.
+ You configure jCIFS as a filter in the web.xml of your webapp. Next, you must configure
+ a second Jetspeed servlet filter, which must be placed right <i>after</i> the jCIFS filter. An example configuration:
+ </p>
+ <source><![CDATA[
+<filter>
+ <filter-name>NtlmHttpFilter</filter-name>
+ <filter-class>jcifs.http.NtlmHttpFilter</filter-class>
+ <init-param>
+ <param-name>jcifs.smb.client.domain</param-name>
+ <param-value>SOME_DOMAIN</param-value>
+ </init-param>
+</filter>
+
+<filter>
+ <filter-name>NtlmHttpServletRequestFilter</filter-name>
+ <filter-class>org.apache.jetspeed.security.impl.ntlm.NtlmHttpServletRequestFilter</filter-class>
+ <init-param>
+ <param-name>org.apache.jetspeed.security.ntlm.ignoreUrls</param-name>
+ <param-value>/login/login</param-value>
+ </init-param>
+</filter>
+
+<filter-mapping>
+ <filter-name>NtlmHttpFilter</filter-name>
+ <url-pattern>/*</url-pattern>
+</filter-mapping>
+
+<filter-mapping>
+ <filter-name>NtlmHttpServletRequestFilter</filter-name>
+ <url-pattern>/*</url-pattern>
+</filter-mapping>]]></source>
+ </subsection>
+ <subsection name="Configuring NTLM Security Valve">
+ <p>
+ The above filters set the correct credentials on the request. To use these credentials, you
+ have to configure the <code>org.apache.jetspeed.security.impl.ntlm.NtlmSecurityValve</code> in the
+ Jetspeed pipelines you want to secure. This Valve can be used as a <i>replacement</i> for the default <code>SecurityValveImpl</code>. For explanation about how to set up pipelines, see
+ <a href="guide-pipeline.html">here</a>. An example of how to configure the NtlmSecurityValve bean:
+ </p>
+ <source>
+ <![CDATA[
+<bean id="securityValve" class="org.apache.jetspeed.security.impl.ntlm.NtlmSecurityValve" init-method="initialize">
+ <constructor-arg>
+ <ref bean="org.apache.jetspeed.security.UserManager" />
+ </constructor-arg>
+ <!-- Network domain. This value is optionally stripped from the authenticated user name -->
+ <constructor-arg><value>SOME_DOMAIN</value></constructor-arg>
+ <!-- Omit domain in user principal -->
+ <constructor-arg><value>true</value></constructor-arg>
+ <!--
+ NTLM Authorization required.
+ If set to true, only users authenticated by NTLM authentication will be authorized.
+ -->
+ <constructor-arg><value>false</value></constructor-arg>
+</bean>]]></source>
+ </subsection>
+ </section>
+ </body>
+</document>
\ No newline at end of file
Modified: portals/jetspeed-2/trunk/xdocs/guides/index.xml
URL: http://svn.apache.org/viewvc/portals/jetspeed-2/trunk/xdocs/guides/index.xml?view=diff&rev=537309&r1=537308&r2=537309
==============================================================================
--- portals/jetspeed-2/trunk/xdocs/guides/index.xml (original)
+++ portals/jetspeed-2/trunk/xdocs/guides/index.xml Fri May 11 15:50:41 2007
@@ -47,7 +47,8 @@
<li><a href="guide-app-servers.html">Guide to application servers configuration</a></li>
<li><a href="guide-security.html">Guide to configuring Jetspeed-2 security</a></li>
<li><a href="guide-sso.html">Guide to using Jetspeed-2 single sign-on</a></li>
- <li><a href="guide-user-attributes.html">Guide to defining user attributes (PLT.17 user information configuration)</a></li>
+ <li><a href="guide-ntlm.html">Guide to using NTLM Authentication</a></li>
+ <li><a href="guide-user-attributes.html">Guide to defining user attributes (PLT.17 user information configuration)</a></li>
<li><a href="guide-profiler.html">Guide to using profilers</a></li>
<li><a href="guide-aggregation.html">Guide to Aggregation</a></li>
<li><a href="guide-subsites.html">Guide to Subsites</a></li>
---------------------------------------------------------------------
To unsubscribe, e-mail: jetspeed-dev-unsubscribe@portals.apache.org
For additional commands, e-mail: jetspeed-dev-help@portals.apache.org