package com.porterhead.rest.filter;
import com.porterhead.rest.config.ApplicationConfig;
import com.porterhead.rest.user.UserRepository;
import com.porterhead.rest.user.UserService;
import com.porterhead.rest.user.api.ExternalUser;
import com.porterhead.rest.user.domain.AuthorizationToken;
import com.porterhead.rest.user.domain.User;
import com.porterhead.rest.user.exception.AuthorizationException;
import com.sun.jersey.spi.container.ContainerRequest;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.joda.time.DateTime;
import org.joda.time.format.ISODateTimeFormat;
import org.junit.Before;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import javax.ws.rs.core.SecurityContext;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.*;
public class SecurityContextFilterTest {
private SecurityContextFilter filter;
private UserRepository userRepository;
private UserService userService;
private ContainerRequest containerRequest;
private ApplicationConfig applicationConfig;
@Before
public void setUp() {
userRepository = mock(UserRepository.class);
userService = mock(UserService.class);
containerRequest = mock(ContainerRequest.class);
applicationConfig = mock(ApplicationConfig.class);
when(applicationConfig.getSessionDateOffsetInMinutes()).thenReturn(30);
when(applicationConfig.requireSignedRequests()).thenReturn(true);
filter = new SecurityContextFilter(userRepository, userService, applicationConfig);
}
@Test
public void noHeadersInRequest() {
when(containerRequest.getHeaderValue(SecurityContextFilter.HEADER_AUTHORIZATION)).thenReturn(null);
when(containerRequest.getHeaderValue(SecurityContextFilter.HEADER_AUTHORIZATION)).thenReturn(null);
containerRequest = filter.filter(containerRequest);
assertThat(containerRequest.getUserPrincipal(), is(nullValue()));
}
@Test
public void validAuthHeaders() {
setUpValidRequest();
containerRequest = filter.filter(containerRequest);
}
private void setUpValidRequest() {
User user = new User();
user.setAuthorizationToken(new AuthorizationToken(user));
final ExternalUser externalUser = new ExternalUser(user);
String dateString = new DateTime().toString(ISODateTimeFormat.dateTimeNoMillis());
String hashedToken = new String(Base64.encodeBase64(DigestUtils.sha256(user.getAuthorizationToken().getToken() + ":user/555,POST," + dateString + ",123")));
when(containerRequest.getHeaderValue(SecurityContextFilter.HEADER_AUTHORIZATION)).thenReturn(externalUser.getId() + ":" + hashedToken);
when(containerRequest.getHeaderValue(SecurityContextFilter.HEADER_DATE)).thenReturn(dateString);
when(containerRequest.getHeaderValue(SecurityContextFilter.HEADER_NONCE)).thenReturn("123");
when(containerRequest.getPath()).thenReturn("user/555");
when(containerRequest.getMethod()).thenReturn("POST");
when(userRepository.findByUuid(user.getUuid().toString())).thenReturn(user);
doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) throws Throwable {
SecurityContext context = (SecurityContext) invocation.getArguments()[0];
ExternalUser user = (ExternalUser) context.getUserPrincipal();
assertThat(user.getId(), is(externalUser.getId()));
return null;
}
}).when(containerRequest).setSecurityContext(any(SecurityContext.class));
}
@Test (expected = AuthorizationException.class)
public void dateHeaderIsOutOfRange() {
User user = new User();
final ExternalUser externalUser = new ExternalUser(user);
when(containerRequest.getHeaderValue(SecurityContextFilter.HEADER_AUTHORIZATION)).thenReturn(externalUser.getId() + ":123");
when(containerRequest.getHeaderValue(SecurityContextFilter.HEADER_DATE)).thenReturn(new DateTime().minusMinutes(10).toString(ISODateTimeFormat.dateTimeNoMillis()));
when(containerRequest.getHeaderValue(SecurityContextFilter.HEADER_NONCE)).thenReturn("123");
when(applicationConfig.getSessionDateOffsetInMinutes()).thenReturn(5);
containerRequest = filter.filter(containerRequest);
}
@Test (expected = AuthorizationException.class)
public void duplicateNonce() throws Exception {
setUpValidRequest();
filter.filter(containerRequest);
Thread.sleep(20); //tolerance limit
//submit same request again with same nonce value
filter.filter(containerRequest);
}
}