通过Filter在Servlet中设置Authentication Header

前言

这是我第一次尝试filter,温柔。

项目描述

我正在尝试为我们的几个应用程序完成SSO的构建,我似乎正在碰壁。 我尝试连接的webapp使用“身份validation”标头来确定应用程序中的用户凭据。 我已经构建了一个filter,希望在将标头传递给webapp之前设置它。

问题

代码通过eclipsevalidation,编译,加载到Tomcat,并传递给webapp。 唯一缺少的是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源码

   AuthenticationFilter AuthenticationFilter  com.xxx.xxx.xxx.filters.AuthenticationFilter   AuthenticationFilter /*  ...  

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 

谢谢你的帮助。

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

我对我的系统进行了测试。 我复制了你的代码,转储了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); } } 

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

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

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

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

我还假设您没有使用基于Java EE容器的身份validation,Tomcat会为您执行此检查。 在这种情况下,filter只是“太晚了”。 在您的filter被调用之前,容器已经做出了决定。

如果您使用的是基于容器的身份validation,并且您的应用程序位于同一个容器中,我会想象Tomcat(或其他人)在容器级别有一个SSO选项。 我知道Glassfish将为您提供开箱即用的function。 如果是这种情况,应该直接修改Tomcat工件(即不是可移植的Java EE / Servlet机制)来实现它。