Get curenntly loged in user Spring - java

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()

Related

Custom UserDetailsService is not called by spring-boot

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.

How to get a password from the data entry field?

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");

Could not Autowire.No Beans of UserDetailService type found

Here is the error details when i run.
APPLICATION FAILED TO START
Description:
Field userDetailsService in com.word.security.WebSecurityConfig
required a bean of type
'org.springframework.security.core.userdetails.UserDetailsService'
that could not be found.
Action:
Consider defining a bean of type
'org.springframework.security.core.userdetails.UserDetailsService' in
your configuration.
Here is the WebSecurityConfig.java class
#Configuration
#EnableWebSecurity
#Service
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Override
protected void configure(HttpSecurity http) throws Exception {
// disable caching
http.headers().cacheControl();
http.csrf().disable() // disable csrf for our requests.
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers(HttpMethod.GET, "/login").permitAll()
.antMatchers(HttpMethod.POST, "/createuser").permitAll()
.antMatchers(HttpMethod.GET, "/user/1").permitAll()
.anyRequest().authenticated()
.and()
// We filter the api/login requests
.addFilterBefore(new JWTLoginFilter("/login", authenticationManager()), UsernamePasswordAuthenticationFilter.class)
// And filter other requests to check the presence of JWT in header
.addFilterBefore(new JWTAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// Create a default account
auth.userDetailsService(userDetailsService());
}
#Bean
public UserDetailsService userDetailsService() {
return super.userDetailsService();
}
}
Intellj IDEA shows the Could not Autowire error for userDetailsService below;
#Autowired
private UserDetailsService userDetailsService;
However, on my another class named SecurityService ;
#Service
public class SecurityService {
#Autowired
IUserService userService;
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private UserDetailsService userDetailsService;
public User activeUser() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String username = auth.getName();
Optional<User> user = userService.getUserByName(username);
if (user.isPresent()) {
return user.get();
}
return null;
}
public void autologin(String username, String password) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(userDetails, password, AuthorityUtils.createAuthorityList("USER"));
authenticationManager.authenticate(usernamePasswordAuthenticationToken);
if (usernamePasswordAuthenticationToken.isAuthenticated()) {
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
}
UPDATE
UserController.Class
#RestController
public class UserController {
#Autowired
private IUserService userService;
#Autowired
private SecurityService securityService;
#RequestMapping(value = "/createuser", method = RequestMethod.POST)
public String createUser(#RequestBody User user, Model md) {
if (userService.checkExistUserName(user.getUserName())) {
md.addAttribute("LoginError", true);
return "bu kullanici adi ile bir kullanici bulunmaktadir. Lutfen baska bir kullanici adi ile deneyiniz";
}
User newUser = new User();
newUser.setUserName(user.getUserName());
newUser.setFirstname(user.getFirstname());
newUser.setUserMail(user.getUserMail());
newUser.setSurname(user.getSurname());
newUser.setUserPassword(user.getUserPassword());
userService.saveUser(user);
/* Automatic login after register */
securityService.autologin(user.getUserName(), user.getUserPassword());
return user.getId().toString();
}
I'm not getting the same error as i have on WebSecurityConfig.java.
But now i m getting the StackoverFlow Error shown below after attempting to create an user;
java.lang.StackOverflowError: null at
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$UserDetailsServiceDelegator.loadUserByUsername(WebSecurityConfigurerAdapter.java:441)
~[spring-security-config-4.2.1.RELEASE.jar:4.2.1.RELEASE] at
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$UserDetailsServiceDelegator.loadUserByUsername(WebSecurityConfigurerAdapter.java:442)
~
its like going into the recursive loop. Dont know how to update.
WebSecurityConfigurerAdapter contains this method:
public UserDetailsService userDetailsServiceBean() throws Exception
From Java Docs:
Override this method to expose a UserDetailsService created from configure(AuthenticationManagerBuilder) as a bean.
So try to override this method in WebSecurityConfig like this:
#Bean
public UserDetailsService userDetailsService() {
return super.userDetailsService();
}
One of the reason for this error is as you do not have implementation of this class. Create a class called CustomUserDetailsService implementing UserDetailsService and annotate it with #Component.
Refer to spring documentation for more.

Spring Security OAuth 2.0 requiring authentication token for anonymous resources

I'm attempting to create a site. The pages that are available to anyone are the landing page, the login page, the register page, the about us page, and the contact page as seen below.
#Configuration
public class CustomWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
private final AuthenticationManager authenticationManager;
#Autowired
public CustomWebSecurityConfigurerAdapter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.parentAuthenticationManager(authenticationManager);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/join", "/login", "/about", "/contact").permitAll()
.and().authorizeRequests()
.anyRequest().authenticated()
.and().exceptionHandling()
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/"))
.and()
.logout().logoutSuccessUrl("/").permitAll()
.and()
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}
}
Here is my OAuth2 config:
#Configuration
#EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("my-client")
.authorizedGrantTypes("client_credentials", "authorization_code")
.authorities("ROLE_CLIENT")
.scopes("read", "write")
.resourceIds("business-resource")
.secret("secret");
}
}
And my controller:
#EnableResourceServer
#RestController
public class BusinessAccountController {
private static final Logger logger = Logger.getLogger(BusinessAccountController.class);
#Autowired
BusinessUserService businessUserService;
/*URL mapping constants for each particular controller method*/
private static final String LOGIN_URL_MAPPING = "/login";
private static final String USER_ENDPOINT_URL_MAPPING = "/user";
private static final String ACCOUNT_CREATION_URL_MAPPING = "/join";
/**
* #param principal
* #return
*/
#RequestMapping(USER_ENDPOINT_URL_MAPPING)
public Principal user(Principal principal) {
return principal;
}
#RequestMapping(value = LOGIN_URL_MAPPING, method = RequestMethod.POST)
public ResponseEntity<BusinessUser> login(#RequestBody BusinessUser inputUser) {
BusinessUser requestedUser = businessUserService.findByUsername(inputUser.getUsername());
if(requestedUser != null)
if(BCrypt.checkpw(inputUser.getPassword(), requestedUser.getPassword()))
return new ResponseEntity<>(requestedUser, HttpStatus.OK);
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
...
For some reason, every single page requires an authentication token(gives a 401 unauthorized response), even the ones I specified permitAll() on (login, contact, about us, etc...). Why is Spring asking for an authentication token for the pages I specified to be accessed without authentication?
Side note: If I generate an access token, I'm able to register, log in, and access unauthorized pages. I want to be able to access the specified pages in my WebSecurityConfigurerAdapter without an authentication token.

Spring security custom login url

I have the following Sprring web app:
#Secured({"ROLE_ADMIN"})
#RequestMapping(value = "data/{id}", method = RequestMethod.GET)
public Object getData(#RequestPath String id)
#RequestMapping(value = "login", method = RequestMethod.GET)
public Object login(#RequestParam String username, #RequestParam String password)
In login I need to call another server, pass credentials and get back roles, then let spring know to use these roles for incoming user.
After login client can use getData method if pass authorization of ROLE_ADMIN.
How can I implement this behaviour using java config?
UPDATE:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public AuthenticationProvider authenticationProvider;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
;
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
}
#Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
private static final Logger logger = LogFactory.getLogger();
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String name = authentication.getName();
String password = authentication.getCredentials().toString();
log.debug("name=" + name + " password=" + password);
List<GrantedAuthority> grantedAuths = new ArrayList<>();
grantedAuths.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
Authentication auth = new UsernamePasswordAuthenticationToken(name, password, grantedAuths);
return auth;
}
#Override
public boolean supports(Class<?> authentication) {
logger.debug("supports authentication=" + authentication);
return true;
}
}
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
But as I can see from the logs CustomAuthenticationProvider.authenticate is never called.
Did I miss something?
Thanks.
UPDATE 2: correct solution for me:
Remove Login url from authentication config
add exception handler to disable redirection in case of authentication error
add success handler to send user valid json response
use http POST for app/login
#EnableGlobalMethodSecurity(securedEnabled = true) in web config in order to allow #Secured annotation in controller.
Thanks for all prompts.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
**.anyRequest().authenticated()**
.and().formLogin()
.loginProcessingUrl("/login").usernameParameter("username")
.passwordParameter("password")
**.successHandler(authenticationSuccessHandler)**.failureHandler(authenticationFailureHandler)
.and().csrf().disable().**exceptionHandling()
.authenticationEntryPoint(errorsAuthenticationEntryPoint)**;
}
You need to use WebSecurityConfigurerAdapter like this:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.logout()
.logoutUrl("/myurl/logout")
.and()
.formLogin()
.loginPage("/myurl/login")
.defaultSuccessUrl("/myurl/login?success");
}
}
Every thing is explain in the documentation https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#jc-form
You will need to implement a custom AuthenticationProvider. Something like:
#Configuration
#EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void registerGlobalAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthenticationProvider());
}
#Bean
AuthenticationProvider customAuthenticationProvider() {
CustomAuthenticationProvider impl = new CustomAuthenticationProvider();
impl.setUserDetailsService(customUserDetailsService());
/* other properties etc */
return impl ;
}
#Bean
UserDetailsService customUserDetailsService() {
/* custom UserDetailsService code here */
}
}

Categories