Preface
This is my first attempt at a Filter, be gentle.
Project Description
I am trying to finalize a build for a SSO for several of our applications and I seem to be hitting a wall. The webapp I am attempting to connect to uses the "Authentication" header to determine user credentials within the application. I have built a Filter with hopes of setting the header before it is passed on to the webapp.
The Problem
The code passes eclipse validation, compiles, loads to Tomcat, and passes through to the webapp. The only thing that is missing is the Authentication header.
What am I missing/doing wrong?
AuthenticationFilter source
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 source
<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-p开发者_如何学Goattern>
</filter-mapping>
...
</web-app>
ServletRequestWrapper Source
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);
}
}
Debug Log
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
Thanks for your help.
I'm adding a new answer, since it's completely different.
I did a test on my system. I copied your code, dumped the cookie test, and wrote a simple Servlet to dump things out for me.
And it worked fine, save for one caveat.
I don't know how your app is using this. But your ServletRequestWrapper
implements getHeaderNames
, and getHeader
, but it does NOT implement getHeaders
. I ran in to that problem as I used getHeaders
to try and dump the request, and, of course, Authorization was missing.
So, you may want to look at your code closer to see if it is indeed not using getHeaders
. If it is, it will "work fine", but completely skip the work you've done, and thus miss your Authorization header.
Here's my implementation, and it worked for me.
@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);
}
}
First, the most basic question (kind of an "is this plugged in" question), I assume that your cookies are all rooted in the same domain, and that you're not trying to get cross domain behavior here. Because cookies won't do that.
Beyond the cookie test, this looks fine. But it all hinges on the cookie test.
If you want to test the Authorization header, then you can simply short circuit the cookie test (i.e. it always passes) and populate the Authorization header with some valid value. This will, in the short term, test your whole Authorization scheme.
Once that's done/fixed, then you can focus on the cookie setting and delivery.
I also assume that you're not using Java EE Container based authentication, with Tomcat doing this check for you. In that case, a filter is simply "too late". The container will have already made it's decisions before your filter even gets called.
If you are using container based authentication, and your apps are on the same container, I would imagine Tomcat (or someone) has an SSO option at the container level. I know that Glassfish will do this for you out of the box. It should be straightforward to modify Tomcat artifacts (i.e. not portable Java EE/Servlet mechanisms) to implement this if that is the case.
精彩评论