Created abstract servlet to handle HMAC

Implemented HMAC authentication in HlsServlet, but disabled it, because
it does not make sense, if you want to support streaming. Also, the path
of recordings can only be obtained by guessing without the HMAC key.
This commit is contained in:
0xboobface 2018-07-07 14:05:07 +02:00
parent aaaca23427
commit 32172fe203
4 changed files with 73 additions and 36 deletions

View File

@ -0,0 +1,47 @@
package ctbrec.recorder.server;
import java.io.BufferedReader;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import ctbrec.Config;
import ctbrec.Hmac;
public abstract class AbstractCtbrecServlet extends HttpServlet {
boolean checkAuthentication(HttpServletRequest req, String body) throws IOException, InvalidKeyException, NoSuchAlgorithmException, IllegalStateException {
boolean authenticated = false;
if(Config.getInstance().getSettings().key != null) {
String reqParamHmac = req.getParameter("hmac");
String httpHeaderHmac = req.getHeader("CTBREC-HMAC");
String hmac = null;
if(reqParamHmac != null) {
hmac = reqParamHmac;
}
if(httpHeaderHmac != null) {
hmac = httpHeaderHmac;
}
byte[] key = Config.getInstance().getSettings().key;
authenticated = Hmac.validate(body, key, hmac);
} else {
authenticated = true;
}
return authenticated;
}
String body(HttpServletRequest req) throws IOException {
StringBuilder body = new StringBuilder();
BufferedReader br = req.getReader();
String line= null;
while( (line = br.readLine()) != null ) {
body.append(line).append("\n");
}
return body.toString().trim();
}
}

View File

@ -6,7 +6,6 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ -18,7 +17,7 @@ import com.iheartradio.m3u8.PlaylistException;
import ctbrec.Config;
public class HlsServlet extends HttpServlet {
public class HlsServlet extends AbstractCtbrecServlet {
private static final transient Logger LOG = LoggerFactory.getLogger(HlsServlet.class);
@ -34,8 +33,24 @@ public class HlsServlet extends HttpServlet {
File recordingsDir = new File(config.getSettings().recordingsDir);
File requestedFile = new File(recordingsDir, request);
// try {
// boolean isRequestAuthenticated = checkAuthentication(req, req.getRequestURI());
// if (!isRequestAuthenticated) {
// resp.setStatus(SC_UNAUTHORIZED);
// String response = "{\"status\": \"error\", \"msg\": \"HMAC does not match\"}";
// resp.getWriter().write(response);
// return;
// }
// } catch (InvalidKeyException | NoSuchAlgorithmException | IllegalStateException e1) {
// resp.setStatus(SC_UNAUTHORIZED);
// String response = "{\"status\": \"error\", \"msg\": \"Authentication failed\"}";
// resp.getWriter().write(response);
// return;
// }
if (requestedFile.getCanonicalPath().startsWith(config.getSettings().recordingsDir)) {
if (requestedFile.getName().equals("playlist.m3u8")) {
try {
servePlaylist(req, resp, requestedFile);
} catch (ParseException | PlaylistException e) {

View File

@ -1,6 +1,7 @@
package ctbrec.recorder.server;
import java.io.IOException;
import java.net.BindException;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
@ -82,8 +83,13 @@ public class HttpServer {
holder = new ServletHolder(hlsServlet);
handler.addServletWithMapping(holder, "/hls/*");
server.start();
server.join();
try {
server.start();
server.join();
} catch (BindException e) {
LOG.error("Port {} is already in use", http.getPort(), e);
System.exit(1);
}
}
public static void main(String[] args) throws Exception {

View File

@ -5,16 +5,12 @@ import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import static javax.servlet.http.HttpServletResponse.SC_OK;
import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
import java.io.BufferedReader;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.util.Iterator;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@ -24,14 +20,12 @@ import org.slf4j.LoggerFactory;
import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.Moshi;
import ctbrec.Config;
import ctbrec.Hmac;
import ctbrec.InstantJsonAdapter;
import ctbrec.Model;
import ctbrec.Recording;
import ctbrec.recorder.Recorder;
public class RecorderServlet extends HttpServlet {
public class RecorderServlet extends AbstractCtbrecServlet {
private static final transient Logger LOG = LoggerFactory.getLogger(RecorderServlet.class);
@ -129,31 +123,6 @@ public class RecorderServlet extends HttpServlet {
}
}
private boolean checkAuthentication(HttpServletRequest req, String body) throws IOException, InvalidKeyException, NoSuchAlgorithmException, IllegalStateException {
boolean authenticated = false;
if(Config.getInstance().getSettings().key != null) {
if(req.getHeader("CTBREC-HMAC") == null) {
authenticated = false;
}
byte[] key = Config.getInstance().getSettings().key;
authenticated = Hmac.validate(body, key, req.getHeader("CTBREC-HMAC"));
} else {
authenticated = true;
}
return authenticated;
}
private String body(HttpServletRequest req) throws IOException {
StringBuilder body = new StringBuilder();
BufferedReader br = req.getReader();
String line= null;
while( (line = br.readLine()) != null ) {
body.append(line).append("\n");
}
return body.toString().trim();
}
private static class Request {
public String action;
public Model model;