package io.mangoo.routing.handlers; import java.time.LocalDateTime; import java.util.HashMap; import java.util.Map; import java.util.Objects; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.google.inject.Inject; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jws; import io.jsonwebtoken.Jwts; import io.mangoo.configuration.Config; import io.mangoo.core.Application; import io.mangoo.enums.ClaimKey; import io.mangoo.enums.Required; import io.mangoo.helpers.RequestHelper; import io.mangoo.helpers.cookie.CookieParser; import io.mangoo.models.Subject; import io.mangoo.routing.Attachment; import io.mangoo.routing.bindings.Authentication; import io.mangoo.routing.bindings.Flash; import io.mangoo.routing.bindings.Form; import io.mangoo.routing.bindings.Session; import io.mangoo.utils.CodecUtils; import io.undertow.server.HttpHandler; import io.undertow.server.HttpServerExchange; import io.undertow.server.handlers.Cookie; /** * * @author svenkubiak * */ public class InboundCookiesHandler implements HttpHandler { private static final Logger LOG = LogManager.getLogger(InboundCookiesHandler.class); private static final int TOKEN_LENGTH = 16; private Config config; private Subject subject; private Form form; @Inject public InboundCookiesHandler(Config config) { this.config = Objects.requireNonNull(config, Required.CONFIG.toString()); } @Override public void handleRequest(HttpServerExchange exchange) throws Exception { Attachment attachment = exchange.getAttachment(RequestHelper.ATTACHMENT_KEY); attachment.setSession(getSessionCookie(exchange)); attachment.setAuthentication(getAuthenticationCookie(exchange)); attachment.setSubject(this.subject); attachment.setFlash(getFlashCookie(exchange)); attachment.setForm(this.form); exchange.putAttachment(RequestHelper.ATTACHMENT_KEY, attachment); nextHandler(exchange); } /** * Retrieves the current session from the HttpServerExchange * * @param exchange The Undertow HttpServerExchange */ protected Session getSessionCookie(HttpServerExchange exchange) { Session session; CookieParser cookieParser = CookieParser.build() .withContent(getCookieValue(exchange, this.config.getSessionCookieName())) .withSecret(this.config.getApplicationSecret()) .isEncrypted(this.config.isSessionCookieEncrypt()); if (cookieParser.hasValidSessionCookie()) { session = Session.build() .withContent(cookieParser.getSessionValues()) .withAuthenticity(cookieParser.getAuthenticity()) .withExpires(cookieParser.getExpiresDate()); } else { session = Session.build() .withContent(new HashMap<>()) .withAuthenticity(RandomStringUtils.randomAlphanumeric(TOKEN_LENGTH)) .withExpires(LocalDateTime.now().plusSeconds(this.config.getSessionExpires())); } return session; } /** * Retrieves the current authentication from the HttpServerExchange * * @param exchange The Undertow HttpServerExchange */ protected Authentication getAuthenticationCookie(HttpServerExchange exchange) { Authentication authentication; final CookieParser cookieParser = CookieParser.build() .withContent(getCookieValue(exchange, this.config.getAuthenticationCookieName())) .withSecret(this.config.getApplicationSecret()) .isEncrypted(this.config.isAuthenticationCookieEncrypt()); if (cookieParser.hasValidAuthenticationCookie()) { authentication = Application.getInstance(Authentication.class) .withExpires(cookieParser.getExpiresDate()) .withAuthenticatedUser(cookieParser.getAuthenticatedUser()) .twoFactorAuthentication(cookieParser.isTwoFactor()); this.subject = new Subject(cookieParser.getAuthenticatedUser(), true); } else { authentication = Application.getInstance(Authentication.class) .withExpires(LocalDateTime.now().plusSeconds(this.config.getAuthenticationExpires())) .withAuthenticatedUser(null); this.subject = new Subject("", false); } return authentication; } /** * Retrieves the flash cookie from the current * * @param exchange The Undertow HttpServerExchange */ @SuppressWarnings("unchecked") protected Flash getFlashCookie(HttpServerExchange exchange) { Flash flash = null; final String cookieValue = getCookieValue(exchange, this.config.getFlashCookieName()); if (StringUtils.isNotBlank(cookieValue)) { try { Jws<Claims> jwsClaims = Jwts.parser() .setSigningKey(this.config.getApplicationSecret()) .parseClaimsJws(cookieValue); Claims claims = jwsClaims.getBody(); final Map<String, String> values = claims.get(ClaimKey.DATA.toString(), Map.class); if (claims.containsKey(ClaimKey.FORM.toString())) { this.form = CodecUtils.deserializeFromBase64(claims.get(ClaimKey.FORM.toString(), String.class)); } flash = new Flash(values); flash.setDiscard(true); } catch (Exception e) { //NOSONAR LOG.error("Failed to parse JWT for flash cookie", e); } } return flash == null ? new Flash() : flash; } /** * Handles the next request in the handler chain * * @param exchange The HttpServerExchange * @throws Exception Thrown when an exception occurs */ @SuppressWarnings("all") protected void nextHandler(HttpServerExchange exchange) throws Exception { Application.getInstance(FormHandler.class).handleRequest(exchange); } /** * Retrieves the value of a cookie with a given name from a HttpServerExchange * * @param exchange The exchange containing the cookie * @param cookieName The name of the cookie * * @return The value of the cookie or null if none found */ private String getCookieValue(HttpServerExchange exchange, String cookieName) { String value = null; final Cookie cookie = exchange.getRequestCookies().get(cookieName); if (cookie != null) { value = cookie.getValue(); } return value; } }