/* * nassh-relay - Relay Server for tunneling ssh through a http endpoint * * Website: https://github.com/zyclonite/nassh-relay * * Copyright 2014-2020 zyclonite networx * http://zyclonite.net * Developer: Lukas Prettenthaler */ package net.zyclonite.nassh.handler; import io.vertx.core.Handler; import io.vertx.core.http.Cookie; import io.vertx.core.http.CookieSameSite; import io.vertx.core.http.HttpServerRequest; import io.vertx.core.http.HttpServerResponse; import io.vertx.core.json.JsonObject; import io.vertx.core.logging.Logger; import io.vertx.core.logging.LoggerFactory; import io.vertx.ext.web.RoutingContext; import net.zyclonite.nassh.model.AuthSession; import net.zyclonite.nassh.util.AuthSessionManager; import net.zyclonite.nassh.util.Constants; import net.zyclonite.nassh.util.RequestHelper; import net.zyclonite.nassh.util.WebHelper; import java.math.BigInteger; import java.security.SecureRandom; import java.util.Scanner; /** * @author zyclonite */ public class CookieHandler implements Handler<RoutingContext> { private static Logger logger = LoggerFactory.getLogger(CookieHandler.class); private static final String STATIC_FILE = "/webroot/auth.html"; private final boolean authentication; private final boolean secureCookie; private final int sessionTTL; private final JsonObject auth; public CookieHandler(final JsonObject config) { this.authentication = config.getBoolean("authentication", true); this.secureCookie = config.getBoolean("secure-cookie", true); this.sessionTTL = config.getInteger("auth-session-timeout", 600); this.auth = config.getJsonObject("auth"); } @Override public void handle(final RoutingContext context) { logger.debug("got request"); final HttpServerRequest request = context.request(); final HttpServerResponse response = context.response(); response.putHeader("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0"); response.putHeader("Pragma", "no-cache"); if (request.params().contains("ext") && request.params().contains("path")) { final String ext = request.params().get("ext"); final String path = request.params().get("path"); if (!authentication) { response.putHeader("location", "chrome-extension://" + ext + "/" + path + "#anonymous@" + RequestHelper.getHost(request)); response.setStatusCode(302); response.end(); return; } final AuthSession authSession = WebHelper.validateCookie(context); if (authSession != null) { final String gplusid = authSession.get("id"); response.putHeader("location", "chrome-extension://" + ext + "/" + path + "#" + gplusid + "@" + RequestHelper.getHost(request)); response.setStatusCode(302); response.end(); } else { response.setStatusCode(200); final String state = new BigInteger(130, new SecureRandom()).toString(32); final AuthSession session = AuthSessionManager.createSession(sessionTTL); session.put("state", state); final Cookie sessionCookie = Cookie .cookie(Constants.SESSIONCOOKIE, session.getId().toString()) .setHttpOnly(true); if (secureCookie) { sessionCookie .setSameSite(CookieSameSite.NONE) .setSecure(true); } response.addCookie(sessionCookie); final String auth_html = new Scanner(this.getClass().getResourceAsStream(STATIC_FILE), "UTF-8") .useDelimiter("\\A").next() .replaceAll("[{]{2}\\s*CLIENT_ID\\s*[}]{2}", auth.getString("client-id")) .replaceAll("[{]{2}\\s*STATE\\s*[}]{2}", state) .replaceAll("[{]{2}\\s*APPLICATION_NAME\\s*[}]{2}", auth.getString("title")); response.end(auth_html); } } else { response.setStatusCode(401); response.end("unauthorized"); } } }