Skip to content

Instantly share code, notes, and snippets.

@neolitec
Created February 12, 2014 11:09
Show Gist options
  • Star 33 You must be signed in to star a gist
  • Fork 21 You must be signed in to fork a gist
  • Save neolitec/8953607 to your computer and use it in GitHub Desktop.
Save neolitec/8953607 to your computer and use it in GitHub Desktop.
HTTP Basic authentication Java filter
package com.neolitec.examples;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.StringTokenizer;
/**
* Created by kemanson on 12/02/14.
*/
public class BasicAuthenticationFilter implements Filter {
/** Logger */
private static final Logger LOG = LoggerFactory.getLogger(BasicAuthenticationFilter.class);
private String username = "";
private String password = "";
private String realm = "Protected";
@Override
public void init(FilterConfig filterConfig) throws ServletException {
username = filterConfig.getInitParameter("username");
password = filterConfig.getInitParameter("password");
String paramRealm = filterConfig.getInitParameter("realm");
if (StringUtils.isNotBlank(paramRealm)) {
realm = paramRealm;
}
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
String authHeader = request.getHeader("Authorization");
if (authHeader != null) {
StringTokenizer st = new StringTokenizer(authHeader);
if (st.hasMoreTokens()) {
String basic = st.nextToken();
if (basic.equalsIgnoreCase("Basic")) {
try {
String credentials = new String(Base64.decodeBase64(st.nextToken()), "UTF-8");
LOG.debug("Credentials: " + credentials);
int p = credentials.indexOf(":");
if (p != -1) {
String _username = credentials.substring(0, p).trim();
String _password = credentials.substring(p + 1).trim();
if (!username.equals(_username) || !password.equals(_password)) {
unauthorized(response, "Bad credentials");
}
filterChain.doFilter(servletRequest, servletResponse);
} else {
unauthorized(response, "Invalid authentication token");
}
} catch (UnsupportedEncodingException e) {
throw new Error("Couldn't retrieve authentication", e);
}
}
}
} else {
unauthorized(response);
}
}
@Override
public void destroy() {
}
private void unauthorized(HttpServletResponse response, String message) throws IOException {
response.setHeader("WWW-Authenticate", "Basic realm=\"" + realm + "\"");
response.sendError(401, message);
}
private void unauthorized(HttpServletResponse response) throws IOException {
unauthorized(response, "Unauthorized");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<filter>
<filter-name>basicAuthenticationFilter</filter-name>
<filter-class>com.neolitec.examples.BasicAuthenticationFilter</filter-class>
<init-param>
<param-name>username</param-name>
<param-value>admin</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>motdepasse</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>basicAuthenticationFilter</filter-name>
<url-pattern>/admin.jsp</url-pattern>
</filter-mapping>
</web-app>
@davidrabinowitz
Copy link

Thanks!

@zzzarius
Copy link

Nice!

@eliotstock
Copy link

Exactly what I was looking for. A gold star for you.

@storysj
Copy link

storysj commented Dec 8, 2015

the line with filterChain.doFilter(servletRequest, servletResponse); needs to be in an else block, otherwise requests with bad credentials will still pass through the filter.

@Sennahoi
Copy link

Sennahoi commented Dec 9, 2015

Thanks for the code. To avoid any timing attacks, you should compare username and password with MessageDigest.isEqual() which is good enough since Java 6u17.

@cynicbox
Copy link

cynicbox commented Feb 9, 2016

Good job!

But Eclipse does not accept the line

throw new Error("Couldn't retrieve authentication", e);

with reason "No exception of type Error can be thrown; an exception type must be a subclass of Throwable"

@yinkn
Copy link

yinkn commented Oct 28, 2016

Recently I have a job to add a simple filter to internal Restful API, things get very simple with your excellent work. Thank Author a lot! and, thank @storysj for his notification.

@nomesh
Copy link

nomesh commented Apr 25, 2017

Awesome @neolitec,
This is the exactly filter I was looking for. Thanks a load and you save my week. cheers !

@saphirepankaj
Copy link

if (!username.equals(_username) || !password.equals(_password)) { unauthorized(response, "Bad credentials"); } else { filterChain.doFilter(servletRequest, servletResponse); }

@ecki
Copy link

ecki commented Nov 18, 2017

It does however not set up a login context (request.login(name, pass)). This is a (somewhat limited) hook into the server security. See also Oracle tutorial on that matter.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment