package com.mastfrog.acteur.cookie.auth;
import com.google.inject.Inject;
import com.mastfrog.acteur.HttpEvent;
import com.mastfrog.acteur.Response;
import com.mastfrog.acteur.headers.Headers;
import static com.mastfrog.acteur.cookie.auth.CookieAuthenticator.DEFAULT_COOKIE_NAME;
import static com.mastfrog.acteur.cookie.auth.CookieAuthenticator.SETTINGS_KEY_COOKIE_HOST;
import static com.mastfrog.acteur.cookie.auth.CookieAuthenticator.SETTINGS_KEY_COOKIE_HTTP_ONLY;
import static com.mastfrog.acteur.cookie.auth.CookieAuthenticator.SETTINGS_KEY_COOKIE_NAME;
import static com.mastfrog.acteur.cookie.auth.CookieAuthenticator.SETTINGS_KEY_USE_COOKIE_HOST;
import static com.mastfrog.acteur.cookie.auth.CookieAuthenticator.SETTINGS_KEY_USE_COOKIE_PORTS;
import com.mastfrog.settings.Settings;
import io.netty.handler.codec.http.Cookie;
import io.netty.handler.codec.http.DefaultCookie;
import java.util.ArrayList;
import java.util.List;
/**
* Actually writes the authentication cookie to the response.
*
* @author Tim Boudreau
*/
final class AuthCookieWriter {
private final String cookieName;
private final boolean useCookieHost;
private final boolean useCookiePorts;
private final boolean cookieHttpOnly;
private final String cookieHost;
private final SessionTimeout timeout;
private final Integer port;
@Inject
AuthCookieWriter(Settings settings, SessionTimeout timeout) {
cookieName = settings.getString(SETTINGS_KEY_COOKIE_NAME, DEFAULT_COOKIE_NAME);
useCookieHost = settings.getBoolean(SETTINGS_KEY_USE_COOKIE_HOST, true);
useCookiePorts = settings.getBoolean(SETTINGS_KEY_USE_COOKIE_PORTS, true);
cookieHttpOnly = settings.getBoolean(SETTINGS_KEY_COOKIE_HTTP_ONLY, true);
cookieHost = settings.getString(SETTINGS_KEY_COOKIE_HOST);
port = settings.getInt("port");
this.timeout = timeout;
}
public String cookieName() {
return cookieName;
}
protected Cookie findCookie(HttpEvent evt) {
Cookie[] cookies = evt.getHeader(Headers.COOKIE);
Cookie cookie = null;
if (cookies != null && cookies.length > 0) {
for (Cookie ck : cookies) {
if (cookieName.equals(ck.getName())) {
cookie = ck;
break;
}
}
}
return cookie;
}
private List<Integer> cookiePorts;
protected List<Integer> cookiePorts() {
if (cookiePorts == null) {
List<Integer> result = new ArrayList<>(3);
result.add(80);
result.add(443);
Integer port = this.port;
if (port != null) {
result.add(port);
}
return cookiePorts = result;
}
return cookiePorts;
}
private boolean logged;
protected void configureCookie(HttpEvent evt, Cookie cookie) {
String cookieHost = this.cookieHost;
if (cookieHost == null) {
cookieHost = evt.getHeader(Headers.HOST);
if (cookieHost != null && cookieHost.lastIndexOf(":") > 0) {
cookieHost = cookieHost.substring(0, cookieHost.lastIndexOf(":"));
}
}
if (cookieHost == null) {
cookieHost = "localhost";
if (!logged) {
logged = true;
System.err.println("cookie.host not set and no host header found - using localhost");
}
}
boolean use = cookieHost == null || (cookieHost != null && !cookieHost.startsWith("localhost"));
if (use) {
// these fail in chrome on localhost
if (useCookieHost) {
cookie.setDomain(cookieHost);
}
if (cookieHttpOnly) {
cookie.setHttpOnly(true);
}
if (useCookiePorts) {
cookie.setPorts(cookiePorts());
}
}
}
/**
* Write the authentication cookie (using the configured name for it)
* to the response.
*
* @param evt The request
* @param cookieValue The value - which should be something opaque and random
* which can be used as a cache key to look up the user on the server side
* @param on
*/
public void setCookie(HttpEvent evt, String cookieValue, Response on) {
DefaultCookie ck = new DefaultCookie(cookieName, cookieValue);
ck.setMaxAge(timeout.get().getStandardSeconds());
configureCookie(evt, ck);
on.add(Headers.SET_COOKIE, ck);
}
public void discardCookie(HttpEvent evt, Response on) {
DefaultCookie cookie = new DefaultCookie(cookieName(), "");
configureCookie(evt, cookie);
cookie.setDiscard(true);
cookie.setMaxAge(0);
on.add(Headers.SET_COOKIE, cookie);
}
}