WebSecurityConfig class
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserService userSevice;
#Autowired
private PasswordEncoder passwordEncoder;
#Bean
public PasswordEncoder getPasswordEncoder() {
return new BCryptPasswordEncoder(8);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/registration", "/static/**", "/about").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userSevice)
.passwordEncoder(passwordEncoder);
}
}
UserService class
public class UserService implements UserDetailsService {
#Autowired
private UserRepo userRepo;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepo.findByUsername(username);
System.out.println(username);
if (user == null) {
throw new UsernameNotFoundException("User not found");
}
return user;
}
}
UserDetailsService displays only the username, but I would like it so that I could still see which password will be entered, I entered system.out.printl(username) for verification, and it displays, And I don’t know how to output the password. They are taken from the database. Thanks in advance .Sorry for my English
So, In essence, what you want is the password sent via the client from AuthenticationManagerBuilder's auth object. If yes, this will not be possible as the passwords are stored in irreversible hashes.
If you want to get the password from DB, you can call user.getPassword().
HttpServletRequest request =((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
String passwordFromForm = request.getParameter("password");
Related
I'm trying to use UserDetailsService in spring-security to implement my authentication logic. However, UserDetailsService is not called during an HTTP request. Here is the code:
#Service
public class CustomUserDetailsService implements UserDetailsService {
#Autowired
private UserService userService;
#Override
public UserDetails loadUserByUsername(String userId) throws UsernameNotFoundException {
Optional<User> user = userService.getById(Long.parseLong(userId));
if (user.isEmpty()) {
throw new UsernameNotFoundException("User " + userId + " not found");
}
return new org.springframework.security.core.userdetails.User(
user.get().getName(),
user.get().getHashedPassword(),
List.of());
}
}
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private CustomUserDetailsService customUserDetailsService;
#Autowired
private PasswordEncoder passwordEncoder;
#Override
protected void configure(HttpSecurity http) throws Exception { // (2)
http.authorizeRequests()
.antMatchers("/user/add", "/user/loginByEmail").permitAll() // (3)
.anyRequest().authenticated()
.and()
.logout()
.permitAll()
.and()
.httpBasic();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailsService)
.passwordEncoder(passwordEncoder);
}
}
I use a test to test the authentication logic, here is the core of the test code:
MvcResult addMvcResult = mockMvc.perform(post("/habit/friend/addById")
.with(SecurityMockMvcRequestPostProcessors.httpBasic("Joey", "password"))
.contentType("application/json")
.content(StringUtils.toJSONString(addFriendRequestByIdDTO)))
.andExpect(status().isOk())
.andReturn();
The log shows that the authentication header is inserted by spring-test:
MockHttpServletRequest:
HTTP Method = POST
Request URI = /habit/friend/addById
Parameters = {}
Headers = [Content-Type:"application/json;charset=UTF-8", Content-Length:"47", Authorization:"Basic Sm9leTpwYXNzd29yZA=="]
Body = {
"currentUserId" : 1,
"friendUserId" : 2
}
Session Attrs = {org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN=org.springframework.security.web.csrf.DefaultCsrfToken#3a48c398}
However, the authentication failed, I got a 403, and CustomUserDetailsService is never called. Why?
Your problem seems to be with CSRF rather than with UserDetailsService's implementation not being registered, Starting from Spring 4.x, CSRF protection is enabled by default and unless you turn it off like
http
.csrf()
.disable()
you are going to get 403 errors.
I try to get curently logged in user in spring using this code
SecurityContextHolder.getContext().getAuthentication().getName();
I have a Configuration Class
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private PasswordEncoderConfig passwordEncoderConfig;
#Autowired
public SecurityConfig(PasswordEncoderConfig passwordEncoderConfig) {
this.passwordEncoderConfig = passwordEncoderConfig;
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
String password = passwordEncoderConfig.passwordEncoder().encode("123");
String password2 = passwordEncoderConfig.passwordEncoder().encode("456");
auth.inMemoryAuthentication().withUser("ram").password(password).roles("USER");
auth.inMemoryAuthentication().withUser("ram1").password(password2).roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic().and()
.authorizeRequests()
.antMatchers("/drug/**").anonymous()
.and().formLogin().permitAll()
.defaultSuccessUrl("/account/show")
.and().logout()
.logoutUrl("/logout")
.invalidateHttpSession(true)
.permitAll()
.and().cors().and().csrf().disable();
}
}
and a Controller
#Controller
#RequestMapping(value = "/account")
public class AccountController {
#Autowired
private UserService userService;
#RequestMapping(value = "/show", method = RequestMethod.GET)
public String showAccount(){
final String currentUserName = SecurityContextHolder.getContext().getAuthentication().getName();
System.out.println(currentUserName);
return "account";
}
}
I want to to get username in the controller, so in that case I woud like to get ram printed in console. Insted it keeps returning anonymousUser even though I logged in as ram. What can I do to get the username?
antMatchers("/account/**").authenticared()
I am new to spring security and want to authenticate users having a userId and password.
The userId is given to users upon registration.
And the second problem is the userId and password are in different tables.
So, how can I customize spring security to meet both requirements.
Here is my security config class.
I am using spring boot 2
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private DbConfig dbConfig;
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/static/**")
.antMatchers(HttpMethod.GET, "/public/**")
.antMatchers(HttpMethod.GET, "/index.html");
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.dataSource(dbConfig.dataSource())
.usersByUsernameQuery("select username,password,active from user where username=?")
.authoritiesByUsernameQuery("select username,authority from authorities where username=?")
.passwordEncoder(passwordEncoder());
}
private PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login")
.permitAll()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/dashboard")
.and()
.csrf()
.disable();
}
}
You'll want to use your own UserDetailsService:
public MyUserDetailsService implements UserDetailsService {
#Override
public User loadUserByUsername(String username) {
// write the query yourself
}
}
And then in your configuration:
#Bean
#Override
public UserDetailsService userDetailsService() {
return new MyUserDetailsService();
}
You can find more details in the section of the Spring Security Reference dedicated to your question.
I created my Custom UserDetailService and Security Config. When I allow to enter to secure page only authorized users - OK, but if users with roles -
HTTP Status 403 – Forbidden.
I think I do not work with roles correctly. Please, help
My UserService
public interface UserService extends UserDetailsService {
}
#Service
public class UserServiceImpl implements UserService{
#Autowired
private PasswordEncoder passwordEncoder;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = new User();
user.setUsername(username);
user.setPassword(passwordEncoder.encode("1"));
//There is the problem I think
List<SimpleGrantedAuthority> roleList = new ArrayList<>();
roleList.add(new SimpleGrantedAuthority("ADMIN"));
user.setRoleList(roleList);
//
user.setAccountNonExpired(true);
user.setAccountNonLocked(true);
user.setCredentialsNonExpired(true);
user.setEnabled(true);
return user;
}
}
Security Config
#Configuration
#EnableWebSecurity
#ComponentScan("something")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserService userService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/admin*").authenticated() - it works
//.antMatchers("/admin*").hasRole("ADMIN") - it doesn't work
.anyRequest().permitAll()
.and()
.formLogin().permitAll()
.and()
.logout().permitAll()
.and().csrf().disable();
}
#Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
My User.class just in case
public class User implements Serializable, UserDetails {
//fields
}
In order to set your user's role to "ADMIN", you need to set the authority to "ROLE_ADMIN".
roleList.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
A role is the same as an authority prefixed with "ROLE_".
The order should be like this:
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/login").permitAll()
.antMatchers("/admins/**").hasRole("ADMIN")
.antMatchers("/users/**").hasAnyRole("ADMIN", "USER")
.anyRequest().authenticated()
.and()
.....
.....
I am using spring spring security 5.1.4 and i am trying to authenticate user with custom authentication.
SecurityConfig
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(
securedEnabled = true,
jsr250Enabled = true,
prePostEnabled = true
)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
CustomUserDetailsService customUserDetailsService;
#Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
#Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter();
}
/* #Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.userDetailsService(customUserDetailsService)
.passwordEncoder(passwordEncoder());
}
*/
#Bean(BeanIds.AUTHENTICATION_MANAGER)
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Autowired
private CustomAuthenticationProvider authProvider;
#Override
protected void configure(
AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authProvider);
}
#Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/",
"/favicon.ico",
"/**/*.png",
"/**/*.gif",
"/**/*.svg",
"/**/*.jpg",
"/**/*.html",
"/**/*.css",
"/**/*.js")
.permitAll()
.antMatchers("/api/auth/**")
.permitAll()
.antMatchers("/app/**").permitAll()
.antMatchers("/api/user/checkUsernameAvailability", "/api/user/checkEmailAvailability")
.permitAll()
.antMatchers(HttpMethod.GET, "/api/polls/**", "/api/users/**")
.permitAll()
.anyRequest()
.authenticated();
// Add our custom JWT security filter
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
and my custom authenticationprovider is
#Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
#Autowired
private UserRepository userRepository;
#Autowired
private PasswordEncoder passwordEncoder;
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String password = authentication.getCredentials().toString();
Optional<Tbluser> dbUser = userRepository.findByUsername(authentication.getName());
Tbluser dUser = dbUser.get();
String dbPassword = dUser.getPassword();
boolean passwordsMatch = passwordEncoder.matches(password,dbPassword);
if(!passwordsMatch) {
throw new BadCredentialsException("Invalid username/password");
}
return new UsernamePasswordAuthenticationToken(username, password, Collections.emptyList());
}
#Override
public boolean supports(Class<?>aClass) {
return aClass.equals(UsernamePasswordAuthenticationToken.class);
}
}
so whenever i debug the password i provide in seen in the plain text i.e in authentication object but the password i fetch from database is encoded form.
boolean passwordsMatch = passwordEncoder.matches(password,dbPassword);
is always false.
how do i authenticate them ?