diff --git a/web/src/main/java/org/springframework/security/web/authentication/rememberme/JdbcTokenRepositoryImpl.java b/web/src/main/java/org/springframework/security/web/authentication/rememberme/JdbcTokenRepositoryImpl.java index 238aaf3c9c..fd23677bc3 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/rememberme/JdbcTokenRepositoryImpl.java +++ b/web/src/main/java/org/springframework/security/web/authentication/rememberme/JdbcTokenRepositoryImpl.java @@ -1,6 +1,22 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.springframework.security.web.authentication.rememberme; import org.springframework.dao.DataAccessException; +import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.SqlParameter; @@ -79,7 +95,11 @@ public class JdbcTokenRepositoryImpl extends JdbcDaoSupport implements Persisten return new PersistentRememberMeToken(rs.getString(1), rs.getString(2), rs.getString(3), rs.getTimestamp(4)); } }, seriesId); - } catch(IncorrectResultSizeDataAccessException moreThanOne) { + } catch(EmptyResultDataAccessException zeroResults) { + if(logger.isInfoEnabled()) { + logger.info("Querying token for series '" + seriesId + "' returned no results.", zeroResults); + } + }catch(IncorrectResultSizeDataAccessException moreThanOne) { logger.error("Querying token for series '" + seriesId + "' returned more than one value. Series" + " should be unique"); } catch(DataAccessException e) { diff --git a/web/src/test/java/org/springframework/security/web/authentication/rememberme/JdbcTokenRepositoryImplTests.java b/web/src/test/java/org/springframework/security/web/authentication/rememberme/JdbcTokenRepositoryImplTests.java index 1d2eefe310..5fa8c46bc3 100644 --- a/web/src/test/java/org/springframework/security/web/authentication/rememberme/JdbcTokenRepositoryImplTests.java +++ b/web/src/test/java/org/springframework/security/web/authentication/rememberme/JdbcTokenRepositoryImplTests.java @@ -1,25 +1,55 @@ +/* + * Copyright 2002-2012 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.springframework.security.web.authentication.rememberme; import static org.junit.Assert.*; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; import java.sql.Timestamp; import java.util.Date; import java.util.List; import java.util.Map; +import org.apache.commons.logging.Log; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.SingleConnectionDataSource; +import org.springframework.test.util.ReflectionTestUtils; /** * @author Luke Taylor */ @SuppressWarnings("unchecked") +@RunWith(MockitoJUnitRunner.class) public class JdbcTokenRepositoryImplTests { + @Mock + private Log logger; + private static SingleConnectionDataSource dataSource; private JdbcTokenRepositoryImpl repo; private JdbcTemplate template; @@ -39,6 +69,7 @@ public class JdbcTokenRepositoryImplTests { @Before public void populateDatabase() { repo = new JdbcTokenRepositoryImpl(); + ReflectionTestUtils.setField(repo, "logger", logger); repo.setDataSource(dataSource); repo.initDao(); template = repo.getJdbcTemplate(); @@ -90,6 +121,19 @@ public class JdbcTokenRepositoryImplTests { assertNull(repo.getTokenForSeries("joesseries")); } + // SEC-1964 + @Test + public void retrievingTokenWithNoSeriesReturnsNull() { + when(logger.isInfoEnabled()).thenReturn(true); + + assertNull(repo.getTokenForSeries("missingSeries")); + + verify(logger).isInfoEnabled(); + verify(logger).info(eq("Querying token for series 'missingSeries' returned no results."), + any(EmptyResultDataAccessException.class)); + verifyNoMoreInteractions(logger); + } + @Test public void removingUserTokensDeletesData() { template.execute("insert into persistent_logins (series, username, token, last_used) values " + diff --git a/web/web.gradle b/web/web.gradle index 9afb8a42e0..eef92d5d75 100644 --- a/web/web.gradle +++ b/web/web.gradle @@ -13,6 +13,7 @@ dependencies { testCompile project(':spring-security-core').sourceSets.test.output, 'commons-codec:commons-codec:1.3', + "org.slf4j:jcl-over-slf4j:$slf4jVersion", "org.springframework:spring-test:$springVersion", "org.powermock:powermock-core:$powerMockVersion", "org.powermock:powermock-api-support:$powerMockVersion",