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