Настройка заголовка аутентификации в сервлете через фильтр - PullRequest
10 голосов
/ 04 февраля 2011

Введение

Это моя первая попытка использования фильтра, будь осторожен.

Описание проекта

Я пытаюсь завершить сборку единого входа для нескольких наших приложений, и мне кажется, что я врезался в стену. Веб-приложение, к которому я пытаюсь подключиться, использует заголовок «Аутентификация» для определения учетных данных пользователя в приложении. Я построил фильтр с надеждой установить заголовок до его передачи в веб-приложение.

Проблема

Код проходит проверку затмения, компилируется, загружается в Tomcat и проходит через веб-приложение. Единственное, чего не хватает - это заголовка аутентификации.

Что я пропускаю / делаю неправильно?

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-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 

Спасибо за вашу помощь.

Ответы [ 2 ]

9 голосов
/ 08 февраля 2011

Я добавляю новый ответ, так как он совершенно другой.

Я провел тест в моей системе. Я скопировал твой код, снял тест cookie и написал простой сервлет, который выложил мне вещи.

И все работало нормально, за исключением одного предупреждения.

Я не знаю, как ваше приложение использует это. Но ваш ServletRequestWrapper реализует getHeaderNames и getHeader, но он НЕ реализует 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 голос
/ 07 февраля 2011

Во-первых, самый основной вопрос (вроде вопроса «это подключено»), я предполагаю, что все ваши куки-файлы укоренены в одном домене, и вы не пытаетесь получить междоменное поведение здесь.Поскольку cookie-файлы этого не делают.

Помимо теста на cookie, это выглядит хорошо.Но все это зависит от теста cookie.

Если вы хотите проверить заголовок авторизации, вы можете просто замкнуть тест cookie (т.е. он всегда проходит) и заполнить заголовок авторизации некоторым допустимым значением.В краткосрочной перспективе это протестирует всю вашу схему авторизации.

После того, как это будет сделано / исправлено, вы можете сосредоточиться на настройке и доставке файлов cookie.

Я также предполагаю, что выне использует аутентификацию на основе Java EE-контейнера, а Tomcat сделает эту проверку за вас.В этом случае фильтр просто «слишком поздно».Контейнер уже примет свои решения еще до того, как ваш фильтр будет вызван.

Если вы используете аутентификацию на основе контейнера, и ваши приложения находятся в одном контейнере, я бы предположил, что Tomcat (или кто-то другой) имеет опцию SSOна уровне контейнера.Я знаю, что Glassfish сделает это для вас из коробки.В этом случае следует легко модифицировать артефакты Tomcat (т.е. не переносимые механизмы Java EE / Servlet).

...