/* * Copyright 2002-2013 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.config.annotation.authentication.configurers.provisioning; import java.util.ArrayList; import java.util.List; import javax.sql.DataSource; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.jdbc.datasource.init.DataSourceInitializer; import org.springframework.jdbc.datasource.init.DatabasePopulator; import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; import org.springframework.security.config.annotation.authentication.ProviderManagerBuilder; import org.springframework.security.core.userdetails.UserCache; import org.springframework.security.provisioning.JdbcUserDetailsManager; /** * Configures an * {@link org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder} * to have JDBC authentication. It also allows easily adding users to the database used * for authentication and setting up the schema. * * <p> * The only required method is the {@link #dataSource(javax.sql.DataSource)} all other * methods have reasonable defaults. * * @param <B> the type of the {@link ProviderManagerBuilder} that is being configured * * @author Rob Winch * @since 3.2 */ public class JdbcUserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>> extends UserDetailsManagerConfigurer<B, JdbcUserDetailsManagerConfigurer<B>> { private DataSource dataSource; private List<Resource> initScripts = new ArrayList<Resource>(); public JdbcUserDetailsManagerConfigurer(JdbcUserDetailsManager manager) { super(manager); } public JdbcUserDetailsManagerConfigurer() { this(new JdbcUserDetailsManager()); } /** * Populates the {@link DataSource} to be used. This is the only required attribute. * * @param dataSource the {@link DataSource} to be used. Cannot be null. * @return * @throws Exception */ public JdbcUserDetailsManagerConfigurer<B> dataSource(DataSource dataSource) throws Exception { this.dataSource = dataSource; getUserDetailsService().setDataSource(dataSource); return this; } /** * Sets the query to be used for finding a user by their username. For example: * * <code> * select username,password,enabled from users where username = ? * </code> * @param query The query to use for selecting the username, password, and if the user * is enabled by username. Must contain a single parameter for the username. * @return The {@link JdbcUserDetailsManagerConfigurer} used for additional * customizations * @throws Exception */ public JdbcUserDetailsManagerConfigurer<B> usersByUsernameQuery(String query) throws Exception { getUserDetailsService().setUsersByUsernameQuery(query); return this; } /** * Sets the query to be used for finding a user's authorities by their username. For * example: * * <code> * select username,authority from authorities where username = ? * </code> * * @param query The query to use for selecting the username, authority by username. * Must contain a single parameter for the username. * @return The {@link JdbcUserDetailsManagerConfigurer} used for additional * customizations * @throws Exception */ public JdbcUserDetailsManagerConfigurer<B> authoritiesByUsernameQuery(String query) throws Exception { getUserDetailsService().setAuthoritiesByUsernameQuery(query); return this; } /** * An SQL statement to query user's group authorities given a username. For example: * * <code> * select * g.id, g.group_name, ga.authority * from * groups g, group_members gm, group_authorities ga * where * gm.username = ? and g.id = ga.group_id and g.id = gm.group_id * </code> * * @param query The query to use for selecting the authorities by group. Must contain * a single parameter for the username. * @return The {@link JdbcUserDetailsManagerConfigurer} used for additional * customizations * @throws Exception */ public JdbcUserDetailsManagerConfigurer<B> groupAuthoritiesByUsername(String query) throws Exception { JdbcUserDetailsManager userDetailsService = getUserDetailsService(); userDetailsService.setEnableGroups(true); userDetailsService.setGroupAuthoritiesByUsernameQuery(query); return this; } /** * A non-empty string prefix that will be added to role strings loaded from persistent * storage (default is ""). * * @param rolePrefix * @return * @throws Exception */ public JdbcUserDetailsManagerConfigurer<B> rolePrefix(String rolePrefix) throws Exception { getUserDetailsService().setRolePrefix(rolePrefix); return this; } /** * Defines the {@link UserCache} to use * * @param userCache the {@link UserCache} to use * @return the {@link JdbcUserDetailsManagerConfigurer} for further customizations * @throws Exception */ public JdbcUserDetailsManagerConfigurer<B> userCache(UserCache userCache) throws Exception { getUserDetailsService().setUserCache(userCache); return this; } @Override protected void initUserDetailsService() throws Exception { if (!initScripts.isEmpty()) { getDataSourceInit().afterPropertiesSet(); } super.initUserDetailsService(); } @Override public JdbcUserDetailsManager getUserDetailsService() { return (JdbcUserDetailsManager) super.getUserDetailsService(); } /** * Populates the default schema that allows users and authorities to be stored. * * @return The {@link JdbcUserDetailsManagerConfigurer} used for additional * customizations */ public JdbcUserDetailsManagerConfigurer<B> withDefaultSchema() { this.initScripts.add(new ClassPathResource( "org/springframework/security/core/userdetails/jdbc/users.ddl")); return this; } protected DatabasePopulator getDatabasePopulator() { ResourceDatabasePopulator dbp = new ResourceDatabasePopulator(); dbp.setScripts(initScripts.toArray(new Resource[initScripts.size()])); return dbp; } private DataSourceInitializer getDataSourceInit() { DataSourceInitializer dsi = new DataSourceInitializer(); dsi.setDatabasePopulator(getDatabasePopulator()); dsi.setDataSource(dataSource); return dsi; } }