package org.sigmah.server.security.impl; /* * #%L * Sigmah * %% * Copyright (C) 2010 - 2016 URD * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU 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 General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #L% */ import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.sigmah.client.page.Page; import org.sigmah.client.security.SecureDispatchAsync.CommandExecution; import org.sigmah.server.dao.AuthenticationDAO; import org.sigmah.server.domain.Authentication; import org.sigmah.server.domain.User; import org.sigmah.server.mapper.Mapper; import org.sigmah.server.security.SecureSessionValidator; import org.sigmah.shared.command.base.Command; import org.sigmah.shared.command.result.Result; import org.sigmah.shared.servlet.ServletConstants.Servlet; import org.sigmah.shared.servlet.ServletConstants.ServletMethod; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.inject.Inject; /** * <p> * The {@link SecureSessionValidator} implementation. * </p> * <p> * This service is used to validate dispatch servlet commands <em>and</em> additional servlet(s) processes. * </p> * * @author Denis Colliot (dcolliot@ideia.fr) * @see org.sigmah.server.dispatch.SecureDispatchServlet * @see org.sigmah.server.servlet.base.AbstractServlet */ public class AuthenticationSecureSessionValidator implements SecureSessionValidator { /** * Logger. */ private static final Logger LOG = LoggerFactory.getLogger(AuthenticationSecureSessionValidator.class); /** * The injected {@code AuthenticationDAO}. */ private final AuthenticationDAO authenticationDAO; /** * The injected {@code Mapper}. */ private final Mapper mapper; /** * AuthenticationSecureSessionValidator initialization. * * @param authenticationDAO * Injected DAO. */ @Inject public AuthenticationSecureSessionValidator(final AuthenticationDAO authenticationDAO, final Mapper mapper) { this.authenticationDAO = authenticationDAO; this.mapper = mapper; } /** * {@inheritDoc} */ @Override public Access validate(final String authenticationToken, final Servlet servlet, final ServletMethod method, final String originPageToken) { return validate(authenticationToken, AccessRights.servletToken(servlet, method), originPageToken); } /** * {@inheritDoc} */ @Override public Access validate(final String authenticationToken, final CommandExecution<? extends Command<?>, ? extends Result> commandExecution) { return validate(authenticationToken, AccessRights.commandToken(commandExecution.getCommand().getClass()), commandExecution.getCurrentPageToken()); } /** * {@inheritDoc} */ @Override public boolean isUserGranted(final User user, final Page page) { return isUserGranted(user, AccessRights.pageToken(page), null); } /** * Validates the access to the given {@code resourceToken} resource for the {@code authenticationToken}. * * @param authenticationToken * The authentication token. * @param resourceToken * The resource token. * @param originPageToken * The origin page token. * @return The validation access result. */ private Access validate(final String authenticationToken, final String resourceToken, final String originPageToken) { if (LOG.isDebugEnabled()) { LOG.debug("Starting validation of authentication token '{}' for resource '{}'.", authenticationToken, resourceToken); } try { if (StringUtils.isBlank(authenticationToken) || "null".equalsIgnoreCase(authenticationToken)) { if (LOG.isTraceEnabled()) { LOG.trace("No authentication token (anonymous user): '{}'.", authenticationToken); } final boolean commandAuthorizedForAnonymous = isUserGranted(null, resourceToken, originPageToken); if (commandAuthorizedForAnonymous) { if (LOG.isTraceEnabled()) { LOG.trace("ACCESS GRANTED for authentication token '{}'.", authenticationToken); } return new Access(AccessType.ACCESS_GRANTED, null); } else { if (LOG.isTraceEnabled()) { LOG.trace("ACCESS UNAUTHORIZED for authentication token '{}'.", authenticationToken); } return new Access(AccessType.UNAUTHORIZED_ACCESS, null); } } // Retrieves the authentication token corresponding user. final Authentication authentication = authenticationDAO.findById(authenticationToken); // Invalid token ? if (authentication == null) { if (LOG.isTraceEnabled()) { LOG.trace("ACCESS UNAUTHORIZED - Invalid session, no Authentication found in database for token '{}'.", authenticationToken); } return new Access(AccessType.INVALID_SESSION, null); } if (authentication.getUser() == null) { if (LOG.isTraceEnabled()) { LOG.trace("ACCESS UNAUTHORIZED - Invalid session, no User for Authentification token '{}'.", authenticationToken); } return new Access(AccessType.INVALID_SESSION, null); } final User user = authentication.getUser(); // Cannot be null at this point. final boolean processAuthorizedForUser = isUserGranted(user, resourceToken, originPageToken); if (processAuthorizedForUser) { if (LOG.isTraceEnabled()) { LOG.trace("ACCESS GRANTED - User '{}' is granted to execute process.", user); } return new Access(AccessType.ACCESS_GRANTED, user); } if (LOG.isTraceEnabled()) { LOG.trace("ACCESS UNAUTHORIZED - User '{}' does not have required permission to execute process.", user); } return new Access(AccessType.UNAUTHORIZED_ACCESS, user); } catch (final Throwable e) { if (LOG.isErrorEnabled()) { LOG.error("Error while validating the authentication token '" + authenticationToken + "'.", e); } return new Access(AccessType.INVALID_SESSION, null); } } /** * Returns the grant access to the given {@code resourceToken} for the {@code user}. * * @param user * The user. * @param resourceToken * The resource token to secure. * @param originPageToken * The origin page token, may be {@code null}. * @return {@code true} if the {@code user} is granted to access {@code resourceToken}, {@code false} otherwise. */ private boolean isUserGranted(final User user, final String resourceToken, final String originPageToken) { if (user != null && BooleanUtils.isFalse(user.getActive())) { if (LOG.isWarnEnabled()) { LOG.warn("User '{}' cannot access resource '{}' because it is no longer active.", user, resourceToken); } return false; } return AccessRights.isGranted(user, resourceToken, originPageToken, mapper); } }