/* * RESTHeart - the Web API for MongoDB * Copyright (C) SoftInstigate Srl * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.restheart.security.handlers; import io.undertow.security.idm.Account; import io.undertow.server.HttpServerExchange; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Optional; import java.util.UUID; import org.restheart.Bootstrapper; import org.restheart.handlers.PipedHttpHandler; import org.restheart.handlers.RequestContext; import static org.restheart.security.handlers.IAuthToken.AUTH_TOKEN_HEADER; import static org.restheart.security.handlers.IAuthToken.AUTH_TOKEN_LOCATION_HEADER; import static org.restheart.security.handlers.IAuthToken.AUTH_TOKEN_VALID_HEADER; import org.restheart.security.impl.AuthTokenIdentityManager; import org.restheart.security.impl.SimpleAccount; /** * * @author Andrea Di Cesare {@literal <andrea@softinstigate.com>} */ public class AuthTokenInjecterHandler extends PipedHttpHandler { private static final boolean enabled = Bootstrapper.getConfiguration().isAuthTokenEnabled(); private static final long TTL = Bootstrapper.getConfiguration().getAuthTokenTtl(); /** * Creates a new instance of AuthTokenInjecterHandler * * @param next */ public AuthTokenInjecterHandler(PipedHttpHandler next) { super(next); } /** * * @param exchange * @param context * @throws Exception */ @Override public void handleRequest(HttpServerExchange exchange, RequestContext context) throws Exception { if (enabled) { if (exchange.getSecurityContext() != null && exchange.getSecurityContext().isAuthenticated()) { Account authenticatedAccount = exchange.getSecurityContext().getAuthenticatedAccount(); char[] token = cacheSessionToken(authenticatedAccount); injectTokenHeaders(exchange, new HeadersManager(exchange), token); } } next(exchange, context); } private void injectTokenHeaders(HttpServerExchange exchange, HeadersManager headers, char[] token) { headers.addResponseHeader(AUTH_TOKEN_HEADER, new String(token)); headers.addResponseHeader(AUTH_TOKEN_VALID_HEADER, Instant.now().plus(TTL, ChronoUnit.MINUTES).toString()); headers.addResponseHeader(AUTH_TOKEN_LOCATION_HEADER, "/_authtokens/" + exchange.getSecurityContext().getAuthenticatedAccount().getPrincipal().getName()); } private char[] cacheSessionToken(Account authenticatedAccount) { String id = authenticatedAccount.getPrincipal().getName(); Optional<SimpleAccount> cachedTokenAccount = AuthTokenIdentityManager.getInstance().getCachedAccounts().get(id); if (cachedTokenAccount == null) { char[] token = UUID.randomUUID().toString().toCharArray(); SimpleAccount newCachedTokenAccount = new SimpleAccount(id, token, authenticatedAccount.getRoles()); AuthTokenIdentityManager.getInstance().getCachedAccounts().put(id, newCachedTokenAccount); return token; } else { return cachedTokenAccount.get().getCredentials().getPassword(); } } }