/** * Copyright (c) 2009 - 2012 Red Hat, Inc. * * This software is licensed to you under the GNU General Public License, * version 2 (GPLv2). There is NO WARRANTY for this software, express or * implied, including the implied warranties of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 * along with this software; if not, see * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. * * Red Hat trademarks are not licensed under GPLv2. No permission is * granted to use or replicate Red Hat trademarks that are incorporated * in this software or its documentation. */ package org.candlepin.resteasy.filter; import org.candlepin.auth.AuthProvider; import org.candlepin.auth.BasicAuth; import org.candlepin.auth.ConsumerPrincipal; import org.candlepin.auth.NoAuthPrincipal; import org.candlepin.auth.OAuth; import org.candlepin.auth.Principal; import org.candlepin.auth.SSLAuth; import org.candlepin.auth.TrustedConsumerAuth; import org.candlepin.auth.TrustedUserAuth; import org.candlepin.common.auth.SecurityHole; import org.candlepin.common.config.Configuration; import org.candlepin.common.exceptions.BadRequestException; import org.candlepin.common.exceptions.NotAuthorizedException; import org.candlepin.config.ConfigProperties; import org.candlepin.model.ConsumerCurator; import org.candlepin.model.DeletedConsumerCurator; import com.google.inject.Inject; import com.google.inject.Injector; import org.jboss.resteasy.spi.HttpRequest; import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import javax.annotation.Priority; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Priorities; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.ResourceInfo; import javax.ws.rs.core.Context; import javax.ws.rs.core.SecurityContext; import javax.ws.rs.ext.Provider; /** * The AuthenticationFilter is responsible for populating the JAXRS SecurityContext */ @Priority(Priorities.AUTHENTICATION) @Provider public class AuthenticationFilter implements ContainerRequestFilter { private static Logger log = LoggerFactory.getLogger(AuthenticationFilter.class); @Context private HttpServletRequest request; private ConsumerCurator consumerCurator; private Injector injector; private Configuration config; private List<AuthProvider> providers = new ArrayList<AuthProvider>(); @Inject public AuthenticationFilter(Configuration config, ConsumerCurator consumerCurator, DeletedConsumerCurator deletedConsumerCurator, Injector injector) { this.consumerCurator = consumerCurator; this.injector = injector; this.config = config; setupAuthStrategies(); } /** * Used to pass mock object during unit testing */ public void setHttpServletRequest(HttpServletRequest request) { this.request = request; } public void setupAuthStrategies() { // use oauth if (config.getBoolean(ConfigProperties.OAUTH_AUTHENTICATION)) { providers.add(injector.getInstance(OAuth.class)); } // http basic auth access if (config.getBoolean(ConfigProperties.BASIC_AUTHENTICATION)) { providers.add(injector.getInstance(BasicAuth.class)); } // consumer certificates if (config.getBoolean(ConfigProperties.SSL_AUTHENTICATION)) { providers.add(injector.getInstance(SSLAuth.class)); } // trusted headers if (config.getBoolean(ConfigProperties.TRUSTED_AUTHENTICATION)) { providers.add(injector.getInstance(TrustedConsumerAuth.class)); providers.add(injector.getInstance(TrustedUserAuth.class)); } } @Override public void filter(ContainerRequestContext requestContext) throws IOException { log.debug("Authentication check for {}", requestContext.getUriInfo().getPath()); HttpRequest httpRequest = ResteasyProviderFactory.getContextData(HttpRequest.class); ResourceInfo resourceInfo = ResteasyProviderFactory.getContextData(ResourceInfo.class); Method method = resourceInfo.getResourceMethod(); SecurityHole hole = method.getAnnotation(SecurityHole.class); Principal principal = null; if (hole != null && hole.anon()) { principal = new NoAuthPrincipal(); } else { for (AuthProvider provider : providers) { principal = provider.getPrincipal(httpRequest); if (principal != null) { log.debug("Establishing principal with {}", provider.getClass().getName()); break; } } } /* At this point, there is no provider that has given a valid principal, * so we use the NoAuthPrincipal here if it is allowed. */ if (principal == null) { if (hole != null && hole.noAuth()) { log.debug("No auth allowed for resource; setting NoAuth principal"); principal = new NoAuthPrincipal(); } else if (!config.getBoolean(ConfigProperties.AUTH_OVER_HTTP) && !request.isSecure()) { throw new BadRequestException("Please use SSL when accessing protected resources"); } else { throw new NotAuthorizedException("Invalid credentials."); } } if (principal instanceof ConsumerPrincipal) { // HACK: We need to do this after the principal has been pushed, // lest our security settings start getting upset when we try to // update a consumer without any roles: ConsumerPrincipal p = (ConsumerPrincipal) principal; consumerCurator.updateLastCheckin(p.getConsumer()); } SecurityContext securityContext = new CandlepinSecurityContext(principal); requestContext.setSecurityContext(securityContext); // Push the principal into the context for the PrincipalProvider to access directly ResteasyProviderFactory.pushContext(Principal.class, principal); } }