2011-02-04 272 views
10

前言通过过滤

这是我在过滤器第一次尝试在Servlet中设置验证头,温柔。

项目描述

我试图完成对SSO构建好我们的应用程序,我似乎击中墙壁。我尝试连接的webapp使用“Authentication”标题来确定应用程序内的用户凭据。我已经构建了一个Filter,希望在将它传递给webapp之前设置标题。

的问题

的代码通过蚀验证,汇编,负载到Tomcat,并穿过所述web应用。唯一缺少的是Authentication标头。

我在想什么/做错了什么?

AuthenticationFilter源

package xxx.xxx.xxx.xxx.filters; 

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.Cookie; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
import javax.servlet.http.HttpSession; 

import xxx.xxx.xxx.ConfigFile; 
import xxx.xxx.xxx.Console; 
import xxx.xxx.xxx.FalseException; 

import xxx.xxx.activity.EncryptUtil; 

public class AuthenticationFilter implements Filter { 
    public ConfigFile config; 

    public void init(FilterConfig arg0) throws ServletException { 
    config = new ConfigFile("C:/config.properties"); 
    } 

    public void doFilter(ServletRequest sRequest, ServletResponse sResponse, FilterChain filterChain) throws IOException, ServletException { 
    Console.debug("AuthenticationFilter.doFilter() triggered."); 
    ServletRequestWrapper request = new ServletRequestWrapper((HttpServletRequest) sRequest); 
    HttpServletResponse response = (HttpServletResponse) sResponse; 
    HttpSession session = request.getSession(); 
    Cookie cookie = null; 
    try { 
     if (request.getParameter("logout") != null) { 
     session.invalidate(); 
     throw new FalseException("Logout recieved"); 
     } 
     String auth = request.getHeader("Authorization"); 
     if (auth == null) { 
     Console.debug("Authorization Header not found."); 
     // get cookie --COOKIE NAME-- 
     Cookie[] cookies = request.getCookies(); 
     if (cookies == null) { 
      throw new FalseException("Cookies not set."); 
     } 
     for (int i = 0; i < cookies.length; i++) { 
      if (cookies[i].getName().equals(config.getProperty("authentication.cookie.name"))) { 
      cookie = cookies[i]; 
      } 
     } 
     if (cookie == null) { 
      throw new FalseException("Cannot find Cookie (" + config.getProperty("authentication.cookie.name") + ") on Client"); 
     } 
     Console.debug("Cookie (" + config.getProperty("authentication.cookie.name") + ") found on Client. value="+cookie.getValue()); 
     String decToken = decryptToken(cookie.getValue()); 
     Console.debug("Decrypted Token: "+decToken); 

     Console.debug("Setting Authorization Header..."); 
     request.setAttribute("Authorization", decToken); 
     request.addHeader("Authorization", decryptToken(cookie.getValue())); 
     Console.debug("Authorization Header set."); 
     Console.debug("Validating Authorization Header value: "+request.getHeader("Authorization")); 
     } 
    }catch (FalseException e) { 
     Console.msg(e.getMessage() + ", giving the boot."); 
     response.sendRedirect(config.getProperty("application.login.url")); 
    } catch (Exception e) { 
     Console.error(e); 
    } 
    Console.debug("AuthenticationFilter.doFilter() finished."); 
    filterChain.doFilter(request, response); 
    } 

    public void destroy() { 

    } 

    private String decryptToken(String encToken) { 
    String token = null; 
    token = EncryptUtil.decryptFromString(encToken); 
    return token; 
    } 
} 

的web.xml源

<web-app> 
    <filter> 
    <filter-name>AuthenticationFilter</filter-name> 
    <display-name>AuthenticationFilter</display-name> 
    <description></description> 
    <filter-class>com.xxx.xxx.xxx.filters.AuthenticationFilter</filter-class> 
    </filter> 
    <filter-mapping> 
    <filter-name>AuthenticationFilter</filter-name> 
    <url-pattern>/*</url-pattern> 
    </filter-mapping> 
    ... 
</web-app> 

了ServletRequestWrapper源

package com.xxx.xxx.xxx.filters; 

import java.util.ArrayList; 
import java.util.Collections; 
import java.util.Enumeration; 
import java.util.HashMap; 
import java.util.Iterator; 
import java.util.List; 
import java.util.Map; 

import javax.servlet.http.HttpServletRequest; 

public class ServletRequestWrapper extends javax.servlet.http.HttpServletRequestWrapper { 

    public ServletRequestWrapper(HttpServletRequest request) { 
    super(request); 
    headerMap = new HashMap(); 
    } 

    private Map headerMap; 

    public void addHeader(String name, String value) { 
    headerMap.put(name, new String(value)); 
    } 

    public Enumeration getHeaderNames() { 
    HttpServletRequest request = (HttpServletRequest) getRequest(); 
    List list = new ArrayList(); 
    for (Enumeration e = request.getHeaderNames(); e.hasMoreElements();) { 
     list.add(e.nextElement().toString()); 
    } 

    for (Iterator i = headerMap.keySet().iterator(); i.hasNext();) { 
     list.add(i.next()); 
    } 
    return Collections.enumeration(list); 
    } 

    public String getHeader(String name) { 
    Object value; 
    if ((value = headerMap.get("" + name)) != null) 
     return value.toString(); 
    else 
     return ((HttpServletRequest) getRequest()).getHeader(name); 
    } 

} 

调试日志

LoginServlet.doGet() triggered. 
[DEBUG] : Authenticate.isClientLoggedIn() triggered. 
xxx url : https://xxx.xxx.xxx/xxx/home.action 
[DEBUG] : Authenticate.isClientLoggedIn() status code: 401 
Unauthorized User. 
Client IS NOT logged in. 

-- Fill out Login Form, submit -- 

LoginServlet.doPost() triggered. 
[DEBUG] : Authenticate.isClientLoggedIn() triggered. 
xxx url : https://xxx.xxx.xxx./xxx/home.action 
[DEBUG] : Authenticate.isClientLoggedIn() status code: 401 
Unauthorized User. 
Client IS NOT logged in. 
Client (--USERID--) attempting basic authentication with password(--PASSWORD--). 
[DEBUG] : BasicAuthentication.touch(http://localhost:PORT/vu/loginCheck.html, --USERID--, --PASSWORD--) triggered. 
[DEBUG] : BasicAuthentication.touch() response code: 200 
Client (--USERID--) has been logged IN. 
Client (--USERID--) basic authentication finished, Client is logged in. 
Client (--USERID--) logged in successfully. 
[DEBUG] : Cookie (xxx_token) Set: 1e426f19ebdfef05dec6544307addc75401ecdc908a3c7e6df5336c744--SECRET-- 
[DEBUG] : Redirecting client to https://xxx.xxx.xxx/xxx/home.action 

-- Redirected to webapp, filter recieves -- 

[DEBUG] : AuthenticationFilter.doFilter() triggered. 
[DEBUG] : Authorization Header not found. << Initical check to see if user is already logged in to site 
[DEBUG] : Cookie (xxx_token) found on Client. value=1e426f19ebdfef05dec6544307addc75401ecdc908a3c7e6df5336c744--SECRET-- 
[DEBUG] : Decrypted Token: Basic --SECRET-- 
[DEBUG] : Setting Authorization Header... 
[DEBUG] : Authorization Header set. 
[DEBUG] : Validating Authorization Header value: Basic --SECRET-- << Value matches Decrypted Token 
[DEBUG] : AuthenticationFilter.doFilter() finished. 

-- Web Application errors out, unable to find Authorization header 

感谢您的帮助。

+3

只是一些建议;请不要抛出Throwable,这是为通常只有JVM作为最后手段才会捕获的非常广泛的错误保留的,并且永远不会在不重新抛出它们的情况下捕获过滤器或过滤器中的异常。 – 2011-02-04 15:24:56

+0

@安德鲁怀特,我会牢记这一点。我试图保持我的过程和错误分开,没有一堆丑陋的if语句。它不能原谅我的行为,只是解释它。 – PseudoNinja 2011-02-04 15:29:17

+0

你说这个编译,但我找不到ServletRequestWrapper上的addHeader()方法。 – highlycaffeinated 2011-02-04 15:34:31

回答

9

我添加了一个新答案,因为它完全不同。

我在我的系统上做过测试。我复制了你的代码,抛弃了cookie测试,并编写了一个简单的Servlet来为我倾倒东西。

它工作得很好,除了一个警告。

我不知道你的应用程序如何使用它。但您的ServletRequestWrapper实施getHeaderNamesgetHeader,但它不实施getHeaders。我遇到了这个问题,因为我使用getHeaders尝试转储请求,当然,授权失踪。

所以,你可能想看看你的代码更接近,看它是否确实不使用getHeaders。如果是,它会“正常工作”,但完全跳过你已完成的工作,从而错过授权标题。

这是我的实现,它为我工作。

@Override 
    public Enumeration getHeaders(String name) { 
     Enumeration e = super.getHeaders(name); 
     if (e != null && e.hasMoreElements()) { 
      return e; 
     } else { 
      List l = new ArrayList(); 
      if (headerMap.get(name) != null) { 
       l.add(headerMap.get(name)); 
      } 
      return Collections.enumeration(l); 
     } 
    } 
1

首先,最基本的问题(类型是“这是插入”的问题),我认为你的cookies都植根于同一个域,并且你不想在这里获得跨域行为。因为cookie不会那样做。

除了cookie测试,这看起来很好。但这一切都取决于cookie测试。

如果您想测试授权标头,那么您可以简单地短接cookie测试(即它总是通过)并使用某个有效值填充授权标头。这将在短期内测试您的整个授权方案。

一旦完成/修复,那么您可以专注于cookie的设置和交付。

我还假设你没有使用基于Java EE容器的身份验证,Tomcat会为你做这个检查。在这种情况下,过滤器“太晚了”。容器在你的过滤器被调用之前已经做出了决定。

如果您使用基于容器的身份验证,并且您的应用程序位于同一个容器中,我会想象Tomcat(或某人)在容器级别具有SSO选项。我知道Glassfish会为你开箱。如果是这种情况,修改Tomcat构件(即不是可移植的Java EE/Servlet机制)以实现此目的应该很简单。