package org.springframework.security.oauth2.provider.client;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.provider.ClientAlreadyExistsException;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.NoSuchClientException;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
public class JdbcClientDetailsServiceTests {
private JdbcClientDetailsService service;
private JdbcTemplate jdbcTemplate;
private EmbeddedDatabase db;
private static final String SELECT_SQL = "select client_id, client_secret, resource_ids, scope, authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, refresh_token_validity from oauth_client_details where client_id=?";
private static final String INSERT_SQL = "insert into oauth_client_details (client_id, client_secret, resource_ids, scope, authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, refresh_token_validity, autoapprove) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
private static final String CUSTOM_INSERT_SQL = "insert into ClientDetails (appId, appSecret, resourceIds, scope, grantTypes, redirectUrl, authorities) values (?, ?, ?, ?, ?, ?, ?)";
@Before
public void setUp() throws Exception {
// creates a HSQL in-memory db populated from default scripts
// classpath:schema.sql and classpath:data.sql
db = new EmbeddedDatabaseBuilder().addDefaultScripts().build();
jdbcTemplate = new JdbcTemplate(db);
service = new JdbcClientDetailsService(db);
}
@After
public void tearDown() throws Exception {
db.shutdown();
}
@Test(expected = NoSuchClientException.class)
public void testLoadingClientForNonExistingClientId() {
service.loadClientByClientId("nonExistingClientId");
}
@Test
public void testLoadingClientIdWithNoDetails() {
jdbcTemplate.update(INSERT_SQL, "clientIdWithNoDetails", null, null,
null, null, null, null, null, null, null);
ClientDetails clientDetails = service
.loadClientByClientId("clientIdWithNoDetails");
assertEquals("clientIdWithNoDetails", clientDetails.getClientId());
assertFalse(clientDetails.isSecretRequired());
assertNull(clientDetails.getClientSecret());
assertFalse(clientDetails.isScoped());
assertEquals(0, clientDetails.getScope().size());
assertEquals(2, clientDetails.getAuthorizedGrantTypes().size());
assertNull(clientDetails.getRegisteredRedirectUri());
assertEquals(0, clientDetails.getAuthorities().size());
assertEquals(null, clientDetails.getAccessTokenValiditySeconds());
assertEquals(null, clientDetails.getAccessTokenValiditySeconds());
}
@Test
public void testLoadingClientIdWithAdditionalInformation() {
jdbcTemplate.update(INSERT_SQL, "clientIdWithAddInfo", null, null,
null, null, null, null, null, null, null);
jdbcTemplate
.update("update oauth_client_details set additional_information=? where client_id=?",
"{\"foo\":\"bar\"}", "clientIdWithAddInfo");
ClientDetails clientDetails = service
.loadClientByClientId("clientIdWithAddInfo");
assertEquals("clientIdWithAddInfo", clientDetails.getClientId());
assertEquals(Collections.singletonMap("foo", "bar"),
clientDetails.getAdditionalInformation());
}
@Test
public void testLoadingClientIdWithSingleDetails() {
jdbcTemplate.update(INSERT_SQL, "clientIdWithSingleDetails",
"mySecret", "myResource", "myScope", "myAuthorizedGrantType",
"myRedirectUri", "myAuthority", 100, 200, "true");
ClientDetails clientDetails = service
.loadClientByClientId("clientIdWithSingleDetails");
assertEquals("clientIdWithSingleDetails", clientDetails.getClientId());
assertTrue(clientDetails.isSecretRequired());
assertEquals("mySecret", clientDetails.getClientSecret());
assertTrue(clientDetails.isScoped());
assertEquals(1, clientDetails.getScope().size());
assertEquals("myScope", clientDetails.getScope().iterator().next());
assertEquals(1, clientDetails.getResourceIds().size());
assertEquals("myResource", clientDetails.getResourceIds().iterator()
.next());
assertEquals(1, clientDetails.getAuthorizedGrantTypes().size());
assertEquals("myAuthorizedGrantType", clientDetails
.getAuthorizedGrantTypes().iterator().next());
assertEquals("myRedirectUri", clientDetails.getRegisteredRedirectUri()
.iterator().next());
assertEquals(1, clientDetails.getAuthorities().size());
assertEquals("myAuthority", clientDetails.getAuthorities().iterator()
.next().getAuthority());
assertEquals(new Integer(100),
clientDetails.getAccessTokenValiditySeconds());
assertEquals(new Integer(200),
clientDetails.getRefreshTokenValiditySeconds());
}
@Test
public void testLoadingClientIdWithSingleDetailsInCustomTable() {
jdbcTemplate.update(CUSTOM_INSERT_SQL, "clientIdWithSingleDetails",
"mySecret", "myResource", "myScope", "myAuthorizedGrantType",
"myRedirectUri", "myAuthority");
JdbcClientDetailsService customService = new JdbcClientDetailsService(
db);
customService
.setSelectClientDetailsSql("select appId, appSecret, resourceIds, scope, "
+ "grantTypes, redirectUrl, authorities, access_token_validity, refresh_token_validity, additionalInformation, autoApproveScopes from ClientDetails where appId = ?");
ClientDetails clientDetails = customService
.loadClientByClientId("clientIdWithSingleDetails");
assertEquals("clientIdWithSingleDetails", clientDetails.getClientId());
assertTrue(clientDetails.isSecretRequired());
assertEquals("mySecret", clientDetails.getClientSecret());
assertTrue(clientDetails.isScoped());
assertEquals(1, clientDetails.getScope().size());
assertEquals("myScope", clientDetails.getScope().iterator().next());
assertEquals(1, clientDetails.getResourceIds().size());
assertEquals("myResource", clientDetails.getResourceIds().iterator()
.next());
assertEquals(1, clientDetails.getAuthorizedGrantTypes().size());
assertEquals("myAuthorizedGrantType", clientDetails
.getAuthorizedGrantTypes().iterator().next());
assertEquals("myRedirectUri", clientDetails.getRegisteredRedirectUri()
.iterator().next());
assertEquals(1, clientDetails.getAuthorities().size());
assertEquals("myAuthority", clientDetails.getAuthorities().iterator()
.next().getAuthority());
}
@Test
public void testLoadingClientIdWithMultipleDetails() {
jdbcTemplate.update(INSERT_SQL, "clientIdWithMultipleDetails",
"mySecret", "myResource1,myResource2", "myScope1,myScope2",
"myAuthorizedGrantType1,myAuthorizedGrantType2",
"myRedirectUri1,myRedirectUri2", "myAuthority1,myAuthority2",
100, 200, "read,write");
ClientDetails clientDetails = service
.loadClientByClientId("clientIdWithMultipleDetails");
assertEquals("clientIdWithMultipleDetails", clientDetails.getClientId());
assertTrue(clientDetails.isSecretRequired());
assertEquals("mySecret", clientDetails.getClientSecret());
assertTrue(clientDetails.isScoped());
assertEquals(2, clientDetails.getResourceIds().size());
Iterator<String> resourceIds = clientDetails.getResourceIds()
.iterator();
assertEquals("myResource1", resourceIds.next());
assertEquals("myResource2", resourceIds.next());
assertEquals(2, clientDetails.getScope().size());
Iterator<String> scope = clientDetails.getScope().iterator();
assertEquals("myScope1", scope.next());
assertEquals("myScope2", scope.next());
assertEquals(2, clientDetails.getAuthorizedGrantTypes().size());
Iterator<String> grantTypes = clientDetails.getAuthorizedGrantTypes()
.iterator();
assertEquals("myAuthorizedGrantType1", grantTypes.next());
assertEquals("myAuthorizedGrantType2", grantTypes.next());
assertEquals(2, clientDetails.getRegisteredRedirectUri().size());
Iterator<String> redirectUris = clientDetails
.getRegisteredRedirectUri().iterator();
assertEquals("myRedirectUri1", redirectUris.next());
assertEquals("myRedirectUri2", redirectUris.next());
assertEquals(2, clientDetails.getAuthorities().size());
Iterator<GrantedAuthority> authorities = clientDetails.getAuthorities()
.iterator();
assertEquals("myAuthority1", authorities.next().getAuthority());
assertEquals("myAuthority2", authorities.next().getAuthority());
assertEquals(new Integer(100),
clientDetails.getAccessTokenValiditySeconds());
assertEquals(new Integer(200),
clientDetails.getRefreshTokenValiditySeconds());
assertTrue(clientDetails.isAutoApprove("read"));
}
@Test
public void testAddClientWithNoDetails() {
BaseClientDetails clientDetails = new BaseClientDetails();
clientDetails.setClientId("addedClientIdWithNoDetails");
service.addClientDetails(clientDetails);
Map<String, Object> map = jdbcTemplate.queryForMap(SELECT_SQL,
"addedClientIdWithNoDetails");
assertEquals("addedClientIdWithNoDetails", map.get("client_id"));
assertTrue(map.containsKey("client_secret"));
assertEquals(null, map.get("client_secret"));
}
@Test(expected = ClientAlreadyExistsException.class)
public void testInsertDuplicateClient() {
BaseClientDetails clientDetails = new BaseClientDetails();
clientDetails.setClientId("duplicateClientIdWithNoDetails");
service.addClientDetails(clientDetails);
service.addClientDetails(clientDetails);
}
@Test
public void testUpdateClientSecret() {
BaseClientDetails clientDetails = new BaseClientDetails();
clientDetails.setClientId("newClientIdWithNoDetails");
service.setPasswordEncoder(new PasswordEncoder() {
public boolean matches(CharSequence rawPassword,
String encodedPassword) {
return true;
}
public String encode(CharSequence rawPassword) {
return "BAR";
}
});
service.addClientDetails(clientDetails);
service.updateClientSecret(clientDetails.getClientId(), "foo");
Map<String, Object> map = jdbcTemplate.queryForMap(SELECT_SQL,
"newClientIdWithNoDetails");
assertEquals("newClientIdWithNoDetails", map.get("client_id"));
assertTrue(map.containsKey("client_secret"));
assertEquals("BAR", map.get("client_secret"));
}
@Test
public void testUpdateClientRedirectURI() {
BaseClientDetails clientDetails = new BaseClientDetails();
clientDetails.setClientId("newClientIdWithNoDetails");
service.addClientDetails(clientDetails);
String[] redirectURI = { "http://localhost:8080",
"http://localhost:9090" };
clientDetails.setRegisteredRedirectUri(new HashSet<String>(Arrays
.asList(redirectURI)));
service.updateClientDetails(clientDetails);
Map<String, Object> map = jdbcTemplate.queryForMap(SELECT_SQL,
"newClientIdWithNoDetails");
assertEquals("newClientIdWithNoDetails", map.get("client_id"));
assertTrue(map.containsKey("web_server_redirect_uri"));
assertEquals("http://localhost:8080,http://localhost:9090",
map.get("web_server_redirect_uri"));
}
@Test(expected = NoSuchClientException.class)
public void testUpdateNonExistentClient() {
BaseClientDetails clientDetails = new BaseClientDetails();
clientDetails.setClientId("nosuchClientIdWithNoDetails");
service.updateClientDetails(clientDetails);
}
@Test
public void testRemoveClient() {
BaseClientDetails clientDetails = new BaseClientDetails();
clientDetails.setClientId("deletedClientIdWithNoDetails");
service.addClientDetails(clientDetails);
service.removeClientDetails(clientDetails.getClientId());
int count = jdbcTemplate.queryForObject(
"select count(*) from oauth_client_details where client_id=?",
Integer.class, "deletedClientIdWithNoDetails");
assertEquals(0, count);
}
@Test(expected = NoSuchClientException.class)
public void testRemoveNonExistentClient() {
BaseClientDetails clientDetails = new BaseClientDetails();
clientDetails.setClientId("nosuchClientIdWithNoDetails");
service.removeClientDetails(clientDetails.getClientId());
}
@Test
public void testFindClients() {
BaseClientDetails clientDetails = new BaseClientDetails();
clientDetails.setClientId("aclient");
service.addClientDetails(clientDetails);
int count = service.listClientDetails().size();
assertEquals(1, count);
}
}