/**
* 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 static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*;
import org.candlepin.auth.Principal;
import org.candlepin.auth.SSLAuth;
import org.candlepin.auth.Verify;
import org.candlepin.auth.permissions.PermissionFactory;
import org.candlepin.common.util.SuppressSwaggerCheck;
import org.candlepin.common.exceptions.ForbiddenException;
import org.candlepin.model.Consumer;
import org.candlepin.model.ConsumerCurator;
import org.candlepin.resteasy.ResourceLocatorMap;
import org.candlepin.test.DatabaseTestFixture;
import com.google.inject.AbstractModule;
import com.google.inject.Module;
import org.jboss.resteasy.core.InjectorFactoryImpl;
import org.jboss.resteasy.core.ValueInjector;
import org.jboss.resteasy.mock.MockHttpRequest;
import org.jboss.resteasy.spi.ApplicationException;
import org.jboss.resteasy.spi.Failure;
import org.jboss.resteasy.spi.HttpRequest;
import org.jboss.resteasy.spi.HttpResponse;
import org.jboss.resteasy.spi.MethodInjector;
import org.jboss.resteasy.spi.ResteasyProviderFactory;
import org.jboss.resteasy.spi.metadata.ResourceLocator;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.slf4j.LoggerFactory;
import org.xnap.commons.i18n.I18n;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import java.lang.reflect.Method;
import java.security.cert.X509Certificate;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.security.auth.x500.X500Principal;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.UriInfo;
@RunWith(MockitoJUnitRunner.class)
public class VerifyAuthorizationFilterTest extends DatabaseTestFixture {
@Inject private ConsumerCurator consumerCurator;
@Inject private Provider<I18n> i18nProvider;
@Inject private StoreFactory storeFactory;
@Inject private SSLAuth sslAuth;
@Inject private ResourceLocatorMap resourceMap;
@Mock private CandlepinSecurityContext mockSecurityContext;
@Mock private ContainerRequestContext mockRequestContext;
private VerifyAuthorizationFilter interceptor;
private StubMethodInjector methodInjector;
private MockHttpRequest mockReq;
public static class StubInjectorFactoryImpl extends InjectorFactoryImpl {
private MethodInjector methodInjector;
public void setMethodInjector(MethodInjector injector) {
this.methodInjector = injector;
}
@Override
public MethodInjector createMethodInjector(ResourceLocator locator, ResteasyProviderFactory factory) {
return methodInjector;
}
}
public static class StubMethodInjector implements MethodInjector {
private Object[] arguments;
@Override
public Object invoke(HttpRequest request, HttpResponse response,
Object target) throws Failure, ApplicationException,
WebApplicationException {
return null;
}
public Object[] getArguments() {
return arguments;
}
public void setArguments(Object[] arguments) {
this.arguments = arguments;
}
@Override
public Object[] injectArguments(HttpRequest request,
HttpResponse response) throws Failure {
return arguments;
}
@Override
public ValueInjector[] getParams() {
return null;
}
@Override
public boolean expectsBody() {
return false;
}
}
protected Module getGuiceOverrideModule() {
return new AuthInterceptorTestModule();
}
@Before
public void setUp() throws NoSuchMethodException, SecurityException {
// Turn logger to INFO level to disable HttpServletRequest logging.
LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
Logger logger = lc.getLogger(AbstractAuthorizationFilter.class);
logger.setLevel(Level.INFO);
ResteasyProviderFactory.getInstance().registerProvider(
StubInjectorFactoryImpl.class);
StubInjectorFactoryImpl factory = (StubInjectorFactoryImpl)
ResteasyProviderFactory.getInstance().getInjectorFactory();
methodInjector = new StubMethodInjector();
factory.setMethodInjector(methodInjector);
ResourceInfo mockInfo = mock(ResourceInfo.class);
Method method = FakeResource.class.getMethod("someMethod", String.class);
when(mockInfo.getResourceMethod()).thenReturn(method);
Class clazz = FakeResource.class;
when(mockInfo.getResourceClass()).thenReturn(clazz);
ResteasyProviderFactory.pushContext(ResourceInfo.class, mockInfo);
ResteasyProviderFactory.pushContext(HttpRequest.class, mockReq);
when(mockRequestContext.getSecurityContext()).thenReturn(mockSecurityContext);
when(mockRequestContext.getUriInfo()).thenReturn(mock(UriInfo.class));
resourceMap.init();
interceptor = new VerifyAuthorizationFilter(i18nProvider, storeFactory, resourceMap);
}
@Test
public void testAccessToConsumer() throws Exception {
mockReq = MockHttpRequest.create("POST",
"http://localhost/candlepin/fake/123");
ResteasyProviderFactory.pushContext(HttpRequest.class, mockReq);
mockReq.setAttribute(ResteasyProviderFactory.class.getName(), ResteasyProviderFactory.getInstance());
Consumer c = createConsumer(createOwner());
methodInjector.setArguments(new Object[] {c.getUuid()});
when(consumerCurator.getConsumer(eq(c.getUuid()))).thenReturn(c);
when(consumerCurator.findByUuid(eq(c.getUuid()))).thenReturn(c);
X500Principal dn = new X500Principal("CN=" + c.getUuid() + ", C=US, L=Raleigh");
// create mock certs to trigger SSLAuth provider
X509Certificate[] certs = new X509Certificate[1];
X509Certificate cert = mock(X509Certificate.class);
when(cert.getSubjectX500Principal()).thenReturn(dn);
certs[0] = cert;
mockReq.setAttribute("javax.servlet.request.X509Certificate", certs);
Principal p = sslAuth.getPrincipal(mockReq);
when(mockSecurityContext.getUserPrincipal()).thenReturn(p);
interceptor.filter(mockRequestContext);
}
@Test(expected = ForbiddenException.class)
public void noAccessToOtherConsumer() throws Exception {
mockReq = MockHttpRequest.create("POST",
"http://localhost/candlepin/fake/123");
ResteasyProviderFactory.pushContext(HttpRequest.class, mockReq);
mockReq.setAttribute(ResteasyProviderFactory.class.getName(), ResteasyProviderFactory.getInstance());
Consumer c = createConsumer(createOwner());
Consumer c2 = createConsumer(createOwner());
methodInjector.setArguments(new Object[] {c2.getUuid()});
when(consumerCurator.getConsumer(eq(c.getUuid()))).thenReturn(c);
when(consumerCurator.findByUuid(eq(c2.getUuid()))).thenReturn(c2);
X500Principal dn = new X500Principal("CN=" + c.getUuid() + ", C=US, L=Raleigh");
// create mock certs to trigger SSLAuth provider
X509Certificate[] certs = new X509Certificate[1];
X509Certificate cert = mock(X509Certificate.class);
when(cert.getSubjectX500Principal()).thenReturn(dn);
certs[0] = cert;
mockReq.setAttribute("javax.servlet.request.X509Certificate", certs);
Principal p = sslAuth.getPrincipal(mockReq);
when(mockSecurityContext.getUserPrincipal()).thenReturn(p);
interceptor.filter(mockRequestContext);
}
/**
* FakeResource simply to create a Method object to pass down into
* the interceptor.
*/
@SuppressSwaggerCheck
@Path("fake")
public static class FakeResource {
@POST
@Path("/{uuid}")
public String someMethod(@Verify(Consumer.class) String uuid) {
return uuid;
}
}
/*
* simple Guice Module to turn our ConsumerCurator into a mock object.
*/
private static class AuthInterceptorTestModule extends AbstractModule {
@Override
protected void configure() {
PermissionFactory factory = mock(PermissionFactory.class);
bind(PermissionFactory.class).toInstance(factory);
ConsumerCurator mockCc = mock(ConsumerCurator.class);
bind(ConsumerCurator.class).toInstance(mockCc);
bind(StoreFactory.class);
bind(FakeResource.class);
}
}
}