Use Cassandra with WebSecurityConfigurerAdapter in Spring Security - spring-security

I want to make a login form with authentication function using username and password.
This is my config with MySQL :
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
...
#Autowired
private DataSource dataSource;
...
#Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.
jdbcAuthentication()
.usersByUsernameQuery(usersQuery)
.authoritiesByUsernameQuery(rolesQuery)
.dataSource(dataSource)
.passwordEncoder(bCryptPasswordEncoder);
}
...
}
Now I want to change to using Cassandra instead. How can I create Cassandra datasource?
Beside I don't know how can the spring-security validate the username and password which submit from login form. What should I do with POST requested function ? (ex :login() in UserController)

If you have something like this
#Bean(name = "dataSource")
public DriverManagerDataSource dataSource() {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setDriverClassName("com.mysql.jdbc.Driver");
driverManagerDataSource.setUrl("jdbc:mysql://localhost:3306/test");
driverManagerDataSource.setUsername("root");
driverManagerDataSource.setPassword("password");
return driverManagerDataSource;
}
Then you should change your driverClassName to org.apache.cassandra.cql.jdbc.CassandraDriver
And your url as well; jdbc:cassandra://localhost:8988/keyspace

Related

Securing Spring Boot with vaadin

Instead of using InMemory Auth I am trying to authenticate with BD user, so a created class user and roles, and added this code to this class
#EnableWebSecurity
#Configuration
public class SecurityConfig extends VaadinWebSecurityConfigurerAdapter {
#Autowired
private CustomUserDetails customUserDetails;
#Autowired
CustomAuthenticationProvider customAuthenticationProvider;
#Override
protected void configure(HttpSecurity http) throws Exception {
// Set default security policy that permits Vaadin internal requests and
// denies all other
super.configure(http);
setLoginView(http, LoginView.class, "/logout");
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//auth.inMemoryAuthentication().withUser("user").password("{noop}userpass").roles("USER");
auth.userDetailsService(customUserDetails).passwordEncoder(passwordEncoder());
}
#Bean
public DaoAuthenticationProvider createDaoAuthenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(customUserDetails);
provider.setPasswordEncoder(passwordEncoder());
return provider;
}
}
But when i try to authenticate it does not accept
There is more than one way to do this, but usually it goes roughly like this. The relevant pieces, the complete solution is too lengthy for SO. There should not be anything Vaadin specific, but just follow Spring documentation on the matter.
#EnableWebSecurity
#Configuration
public class SecurityConfig extends VaadinWebSecurityConfigurerAdapter {
...
private final UserDetailsService userDetailsService;
#Autowired
public SecurityConfig (UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
super.configure(auth);
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
}
...
}
And then implement UserDetailsService according to Spring spec.
#Service
#Primary
public class UserDetailsServiceImpl implements UserDetailsService {
...
#Autowired
private UserRepository repository; // or what ever you have named it ...
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// implement this according to your actual implementation of user database
}
}

Spring EnableAuthorizationServer with custom AuthenticationManager

I am setting up an OAuth2 + OpenID connect server using Spring security. I have been trying to use the automatic /oauth/token & /oauth/authorize endpoints that are defined when you use the #EnableAuthorizationServer annotation on a class.
#Configuration
#EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter{
In the same class, I have autowired an AuthenticationManager to use in configuring the AuthorizationServerEndpointsConfigurer. I have debugged & confirmed that the correct bean is being autowired.
#Autowired
private AuthenticationManager authMan;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception{
endpoints
.tokenStore(tokenStore())
.userApprovalHandler(userApprovalHandler())
.authenticationManager(authMan);
}
The problem is, there are two WebSecurityConfigurers being created, the one I defined and what appears to be the default WebSecurityConfigurer. Here is part of the one I defined:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
#Autowired
private UserDetailsSrvc detailsSrvc;
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider
= new DaoAuthenticationProvider();
authProvider.setUserDetailsService(detailsSrvc);
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
#Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
#Override
#Bean(name="myAuthenticationManager")
public AuthenticationManager authenticationManagerBean() throws Exception {
return authenticationManager();
}
Unfortunately, the default is being called when I navigate to localhost:8080/outh/token with my browser. I can tell because my custom UserDetailsService is not being used during the authentication, and because I put a breakpoint on the getWebSecurityConfigurers method in org.springframework.security.config.annotation.web.configuration.AutowiredWebSecurityConfigurersIgnoreParents:
#SuppressWarnings({ "rawtypes", "unchecked" })
public List<SecurityConfigurer<Filter, WebSecurity>> getWebSecurityConfigurers() {
List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = new ArrayList<SecurityConfigurer<Filter, WebSecurity>>();
Map<String, WebSecurityConfigurer> beansOfType = beanFactory
.getBeansOfType(WebSecurityConfigurer.class);
for (Entry<String, WebSecurityConfigurer> entry : beansOfType.entrySet()) {
webSecurityConfigurers.add(entry.getValue());
}
return webSecurityConfigurers;
}
The beansOfType map has two entries, but only if I have a class with the #EnableAuthorizationServer annotation. (Only 1 if I comment out annotation)
How do I get my AuthorizationServerConfigurerAdapter (or whatever is actually processing the requests to /oauth/token) to use the WebSecurityConfigurer defined in my WebSecurityConfigurerAdapter? I believe I can get around this issue by defining my own endpoints, and maybe that's the only solution, but I was hoping to utilize the default endpoints.

authenticationFilter is not getting invoked in spring security

I having requirement of passing extra parameter along with username and password in spring security authentication process. After reading several threads I added custom authentication filter in spring security chain
below are my files
Filter class
public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter {
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
String role = request.getParameter("role");
request.getSession().setAttribute("role", role);
return super.attemptAuthentication(request, response);
}
SecurityConfig class
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
RestAuthenticationSuccessHandler customizeAuthenticationSuccessHandler;
#Autowired
RestAuthenticationFailureHandler restAuthenticationFailureHandler;
#Autowired
UserDetailsService userDetailsService;
#Autowired
PasswordEncoder passwordEncoder;
#Autowired
private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
#Autowired
private AccessDeniedHandler restAccessDeniedHandler;
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests().antMatchers("/api/common/**").permitAll()
.antMatchers("/api/student/**").access("hasRole('ROLE_STUDENT')")
.antMatchers("/api/staff/**").access("hasRole('ROLE_STAFF')").antMatchers("/sysAdmin/**").access("hasRole('ROLE_ADMIN')").and().formLogin()
.loginProcessingUrl("/api/common/login")
.successHandler(customizeAuthenticationSuccessHandler)
.failureHandler(restAuthenticationFailureHandler)
.usernameParameter("userName")
.passwordParameter("password")
.and().exceptionHandling().authenticationEntryPoint(restAuthenticationEntryPoint).accessDeniedHandler(restAccessDeniedHandler)
.and().csrf().disable();
}
#Bean
public UsernamePasswordAuthenticationFilter authenticationFilter() throws Exception {
AuthenticationFilter authFilter = new AuthenticationFilter();
authFilter.setUsernameParameter("username");
authFilter.setPasswordParameter("password");
authFilter.setAuthenticationManager(authenticationManagerBean());
return authFilter;
}
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authProvider());
}
public AuthenticationProvider authProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setPasswordEncoder(passwordEncoder);
return provider;
}
}
Problem:
When I tried to authenticate user attemptAuthentication method of my custom filter class is not getting invoked and call directly go to UserDetails service class
Added FilterProcessingUrl to authenticateFilter object resolved the issue.
Updated authenticationFilter() method :
#Bean
public AuthenticationFilter authenticationFilter() throws Exception {
AuthenticationFilter authFilter = new AuthenticationFilter();
authFilter.setUsernameParameter("userName");
authFilter.setPasswordParameter("password");
authFilter.setFilterProcessesUrl("/api/common/login");
authFilter.setAuthenticationSuccessHandler(customizeAuthenticationSuccessHandler);
authFilter.setAuthenticationFailureHandler(restAuthenticationFailureHandler);
authFilter.setAuthenticationManager(authenticationManagerBean());
return authFilter;
}

spring security 4 java config to encrypt password with jpa

I need a login strategy to work with a mysql db. My user table has md5 password encryption.
I need to develop login. My code won't work. Here is my SecutiryConfig:
#Configuration
#EnableWebSecurity
#EnableGlobalAuthentication
#ComponentScan("org.ebook.*")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
Environment env;
#Autowired
private UserRepository userRepository;
#Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(new UserService(userRepository)).passwordEncoder(passwordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/").hasAnyRole("USER", "ADMIN").antMatchers("/index")
.hasAnyRole("USER", "ADMIN").antMatchers("/dashboard").hasAnyRole("USER", "ADMIN")
.antMatchers("/login").hasRole("ANONYMOUS").and().formLogin().loginPage("/login")
.defaultSuccessUrl("/dashboard").usernameParameter("username")
.passwordParameter("password").and().rememberMe()
.tokenValiditySeconds(Integer.parseInt(env.getProperty("session.tokenValidity")))
.key(env.getProperty("session.key")).and().logout().logoutSuccessUrl("/login").and()
.exceptionHandling().accessDeniedPage("/403").and().csrf();
}
#Bean
public Md5PasswordEncoder passwordEncoder(){
Md5PasswordEncoder encoder = new Md5PasswordEncoder();
return encoder;
}
}
And hre is my UserService:
#Service
#Transactional(readOnly = true)
public class UserService implements UserDetailsService {
private UserRepository userRepository;
#Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
org.fingerlinks.ebook.model.bean.User user = null;
if (userRepository!=null) {
user = userRepository.findByUsername(username);
}
if (user != null) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
return new User(user.getUsername(), user.getPassword(), authorities);
}
throw new UsernameNotFoundException("User '" + username + "' not found");
}
}
My problem is that user, in login page, can't login if I use passwordEncoder with an encrypted password on user table.
But if I remove encoding in java code and in user table, all work well.
Can anyone help me to understand where is the terrible mistake?
I'm using spring 4.1.6 and spring security 4.0.2.
Try this while saving user password:
Md5PasswordEncoder encoder = new Md5PasswordEncoder();
user.setPassword(encoder.encode(user.getPassword()));
Spring security encode the entered password and checks against the database password.
In your case you are storing the plain password not the encoded password in the database. Encode the password using Md5PasswordEncoder and store it in the database.

Spring Security Java Config Multiple Group Search Base

I am using Spring Security 3.2.5 with Java config and LDAP authentication/authorization.
We have a requirement to search for groups in two separate trees in LDAP.
ou=groups
and
ou=Groups,ou=webapps,ou=Applications
I have searched and have been unable to find any information on this topic.
This is my current code which is working fine:
#Autowired
public void configureGlobal(UserDetailsContextMapper userDetailsContextMapper, LdapContextSource contextSource, AuthenticationManagerBuilder builder) throws Exception {
builder
.ldapAuthentication()
.userDetailsContextMapper(userDetailsContextMapper)
.contextSource(contextSource)
.userSearchFilter("cn={0}")
.userSearchBase("ou=Users")
.groupSearchBase("ou=groups");
}
I want to do something like this:
builder
.ldapAuthentication()
.userDetailsContextMapper(userDetailsContextMapper)
.contextSource(contextSource)
.userSearchFilter("cn={0}")
.userSearchBase("ou=Users")
.groupSearchBase("ou=groups")
.groupSearchBase("ou=Groups,ou=webapps,ou=Applications");
Which understandably does not work.
Anyone have any pointers on where to start?
My solution was to create an implementation of org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator which can call multiple instances of LdapAuthoritiesPopulator. Then create one LdapAuthoritiesPopulatorfor each 'groupSearchBase' that I wanted to query.
#Autowired
public void configureGlobal(UserDetailsContextMapper userDetailsContextMapper, LdapContextSource contextSource, AuthenticationManagerBuilder builder) throws Exception {
MultipleLdapAuthoritiesPopulator multipleLdapAuthoritiesPopulator = new MultipleLdapAuthoritiesPopulator(
new DefaultLdapAuthoritiesPopulator(contextSource, "ou=Groups,ou=webapps,ou=Applications"),
new DefaultLdapAuthoritiesPopulator(contextSource, "ou=groups"));
builder
.ldapAuthentication()
.ldapAuthoritiesPopulator(multipleLdapAuthoritiesPopulator)
.userDetailsContextMapper(userDetailsContextMapper)
.contextSource(contextSource)
.userSearchFilter("cn={0}")
.userSearchBase("ou=Users");
}
class MultipleLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator {
private List<LdapAuthoritiesPopulator> authoritiesPopulators;
public MultipleLdapAuthoritiesPopulator(LdapAuthoritiesPopulator...authoritiesPopulators) {
this.authoritiesPopulators = asList(authoritiesPopulators);
}
#Override
public Collection<? extends GrantedAuthority> getGrantedAuthorities(DirContextOperations userData, String username) {
List<GrantedAuthority> grantedAuthorities = authoritiesPopulators.stream()
.map(authPopulator -> authPopulator.getGrantedAuthorities(userData, username))
.flatMap(Collection::stream)
.collect(Collectors.toList());
return grantedAuthorities;
}
}

Resources