This is
continuation to my previous post. In previous post, we are storing user
credentials such as password in plain text. Storing password as plain text
leads to security risk. Let’s leverage the application using bcrypt. bcrypt is
a password hashing function designed by Niels Provos and David Mazières, based
on the Blowfish cipher, and presented at USENIX in 1999.
Spring has
built-in support for bcrypt function.
Step 1:
Create a bean of type
'BCryptPasswordEncoder'
@Bean
public
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(16);
}
@Configuration @EnableWebSecurity public class ApplicationSecurityConfiguration extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsServiceImpl userDetailsService; @Autowired private PasswordEncoder passwordEncoder; @Bean public DaoAuthenticationProvider authenticationProvider() { DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider(); daoAuthenticationProvider.setUserDetailsService(userDetailsService); daoAuthenticationProvider.setPasswordEncoder(passwordEncoder); return daoAuthenticationProvider; } ..... ..... }
Step 3:
Use password encoder
while creating new user entities.
User user1
= new User();
user1.setUserName("krishna");
user1.setPassword(passwordEncoder().encode("password123"));
Total
project structure looks like below.
Find the
below working application.
User.java
package com.sample.app.model; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "user") public class User { @Id @Column(name = "user_id") @GeneratedValue private int id; @Column(name = "user_name", nullable = false, unique = true) private String userName; @Column(name = "user_password", nullable = false) private String password; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
UserPrincipal.java
package com.sample.app.model; import java.util.Arrays; import java.util.Collection; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; public class UserPrincipal implements UserDetails { private static final long serialVersionUID = 1L; private User user; public UserPrincipal(final User user) { super(); this.user = user; } @Override public Collection<? extends GrantedAuthority> getAuthorities() { SimpleGrantedAuthority authority1 = new SimpleGrantedAuthority("USER"); SimpleGrantedAuthority authority2 = new SimpleGrantedAuthority("ADMIN"); return Arrays.asList(authority1, authority2); } @Override public String getPassword() { return user.getPassword(); } @Override public String getUsername() { return user.getUserName(); } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return true; } }
UserRepository.java
package com.sample.app.repository; import org.springframework.data.jpa.repository.JpaRepository; import com.sample.app.model.User; public interface UserRepository extends JpaRepository<User, Integer> { User findByUserName(String userName); }
UserDetailsServiceImpl.java
package com.sample.app.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import com.sample.app.model.User; import com.sample.app.model.UserPrincipal; import com.sample.app.repository.UserRepository; @Service public class UserDetailsServiceImpl implements UserDetailsService{ @Autowired private UserRepository userRepository; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUserName(username); if(user == null) { throw new UsernameNotFoundException("User not exist"); } return new UserPrincipal(user); } }
EmployeeController.java
package com.sample.app.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("employees/") public class EmployeeController { @RequestMapping(value = "registered/count", method = RequestMethod.GET) public String countEmps() { return "Total Registered Employees : "+ 1024; } }
HelloWorldController.java
package com.sample.app.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloWorldController { @RequestMapping("/") public String homePage() { return "Welcome to Spring boot Application Development using Spring Security"; } @RequestMapping("/public/aboutme") public String aboutMe() { return "I am securied by spring security module"; } }
ApplicationSecurityConfiguration.java
package com.sample.app.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.password.PasswordEncoder; import com.sample.app.service.UserDetailsServiceImpl; @Configuration @EnableWebSecurity public class ApplicationSecurityConfiguration extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsServiceImpl userDetailsService; @Autowired private PasswordEncoder passwordEncoder; @Bean public DaoAuthenticationProvider authenticationProvider() { DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider(); daoAuthenticationProvider.setUserDetailsService(userDetailsService); daoAuthenticationProvider.setPasswordEncoder(passwordEncoder); return daoAuthenticationProvider; } @Override protected void configure(HttpSecurity httpSecurity) throws Exception { httpSecurity.csrf().disable().authorizeRequests().antMatchers("/", "/public/*", "/css/*", "/js/*").permitAll() .anyRequest().authenticated().and().httpBasic(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception{ auth.authenticationProvider(authenticationProvider()); } }
App.java
package com.sample.app; import com.sample.app.model.User; import java.util.Arrays; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import com.sample.app.repository.UserRepository; @SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } @Bean public CommandLineRunner demo(UserRepository userRepository) { return (args) -> { User user1 = new User(); user1.setUserName("krishna"); user1.setPassword(passwordEncoder().encode("password123")); User user2 = new User(); user2.setUserName("ram"); user2.setPassword(passwordEncoder().encode("ram123")); userRepository.saveAll(Arrays.asList(user1, user2)); }; } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(16); } }
application.properties
logging.level.root=WARN logging.level.org.hibernate=ERROR ## H2 specific properties spring.h2.console.enabled=true spring.h2.console.path=/h2 spring.datasource.url=jdbc:h2:file:~/db/myOrg.db;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=-1; spring.datasource.username=krishna spring.datasource.password=password123 spring.datasource.driverClassName=org.h2.Driver ## JPA specific properties # Creates the schema, destroying previous data. spring.jpa.hibernate.ddl-auto=create spring.jpa.database-platform=org.hibernate.dialect.H2Dialect #spring.jpa.show-sql=true #spring.jpa.properties.hibernate.format_sql=true ## Database connection pooling properties # Number of ms to wait before throwing an exception if no connection is available. spring.datasource.max-wait=10000 # Maximum number of active connections that can be allocated from this pool at the same time. spring.datasource.tomcat.max-active=10 spring.datasource.tomcat.max-idle=5 spring.datasource.tomcat.min-idle=3 spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>springSecurity</groupId> <artifactId>springSecurity</artifactId> <version>1</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.6.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> </dependencies> </project>
Run
App.java.
Open the url 'http://localhost:8080/employees/registered/count', you will be prompted with user credentials.
Enter username as 'krishna' and password as 'password123' and click on OK button.
You can
download complete working application from this link.
No comments:
Post a Comment