I've created this straightforward controller:
#RestController
#RequestMapping("/orders")
public class OrderController {
#GetMapping("/list")
#PreAuthorize(value = "hasRole('VIEWER')")
public List<String> list() {
return new ArrayList<String>();
}
}
As you can see, it's protected by #PreAuthorize(value = "hasRole('VIEWER')").
According to logs:
Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken#99305100: Principal: username; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: VIEWER
Voter: org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter#4799314a, returned: -1
Voter: org.springframework.security.access.vote.RoleVoter#41e7ad2c, returned: 0
Voter: org.springframework.security.access.vote.AuthenticatedVoter#79a89d7d, returned: 0
Access is denied (user is not anonymous); delegating to AccessDeniedHandler
org.springframework.security.access.AccessDeniedException: Access is denied
As you can see, user is authenticated and has role VIEWER. However, it's NOT able to reach _/orders/list endpoint since "access is denied".
Previous log snippet:
Principal: username; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: VIEWER
My JWTFilter looks like:
package com.tsystems.covid.marketplace.backend.config.security;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
public class JWTAuthorizationFilter extends OncePerRequestFilter {
private static final Logger LOG = LoggerFactory.getLogger(JWTAuthorizationFilter.class);
private TokenProperties tokenProperties;
public JWTAuthorizationFilter(
TokenProperties tokenProperties
) {
this.tokenProperties = tokenProperties;
}
#Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain
) throws ServletException, IOException {
Claims claims = this.getAuthorizationToken(request)
.map(this::validateToken)
.orElse(null);
if (null != claims) {
this.setUpAuthentication(claims);
}
filterChain.doFilter(request, response);
}
/**
*
* #param request
* #return
*/
private Optional<String> getAuthorizationToken(HttpServletRequest request) {
return Optional
.ofNullable(request.getHeader(SecurityConstants.AUTHORIZATION_HEADER))
.filter(header -> header.startsWith(SecurityConstants.TOKEN_PREFIX))
.map(header -> header.replace(SecurityConstants.TOKEN_PREFIX, ""));
}
/**
*
* #param token
* #return
*/
private Claims validateToken(String token) {
return Jwts.parser()
.setSigningKey(this.tokenProperties.getSecret())
.parseClaimsJws(token)
.getBody();
}
/**
*
* #param claims
*/
private void setUpAuthentication(Claims claims) {
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
claims.getSubject(),
null,
this.parseAuthorities((List<String>)claims.get(SecurityConstants.JWT_AUTHORITIES_CLAIM))
);
SecurityContextHolder.getContext().setAuthentication(auth);
}
/**
*
* #param authorities
* #return
*/
private List<GrantedAuthority> parseAuthorities(List<String> authorities) {
return authorities
.stream()
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toList());
}
}
Any ideas?
I think it's because the default prefix of spring
try to make this
#RestController
#RequestMapping("/orders")
public class OrderController {
#GetMapping("/list")
#PreAuthorize(value = "hasRole('ROLE_VIEWER')")
public List<String> list() {
return new ArrayList<String>();
}
}
because spring add ROLE_ before the role by default
You give Granted Authorities: VIEWER then u need to use hasAuthority.
#PreAuthorize(value = "hasAuthority('VIEWER')")
If you want to use hasRole then pass Granted Authorities: ROLE_VIEWER then u can use this:
#PreAuthorize(value = "hasRole('VIEWER')")
Related
Both methods, "createToken" and "getAuthentication" return errors when being used in class "JWTAuthenticationFilter" and "JWTAuthorizationFilter". The errors are Non-static method 'getAuthentication(java.lang.String)' cannot be referenced from a static context
The problem is that I don't have a single static field in all my code, so I don't understand the error. I also can't just declare the methods as static because I need to use the variable "jwt_secret" and in my previous post someone explained why I shouldn't make it static:
"Spring will not inject (autowire) into static fields.; that wouldn't make any sense even if it could. Spring beans are instances of classes, but static fields are not associated to any one instance. There are some ugly workarounds but better would be to eliminate the use of static fields."
TokenUtils
package com.XX.ZZ.security;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.stereotype.Component;
import java.util.*;
#Component
public class TokenUtils {
#Autowired
#Value("${custom.data.jwt.secret}")
private final String jwt_secret;
public TokenUtils(String jwtSecret) {
jwt_secret = jwtSecret;
}
public String createToken(String name, String email){
long expirationTime = 86400 * 1000;
Date expirationDate = new Date(System.currentTimeMillis() + expirationTime);
Map<String, Object> extra = new HashMap<>();
extra.put("name", name);
return Jwts.builder()
.setSubject(email)
.setExpiration(expirationDate)
.addClaims(extra)
.signWith(Keys.hmacShaKeyFor(jwt_secret.getBytes()))
.compact();
}
public UsernamePasswordAuthenticationToken getAuthentication(String token){
try {
Claims claims = Jwts.parserBuilder()
.setSigningKey(jwt_secret.getBytes())
.build()
.parseClaimsJws(token)
.getBody();
String email = claims.getSubject();
return new UsernamePasswordAuthenticationToken(email, null, Collections.emptyList());
} catch (JwtException e){
return null;
}
}
}
JWTAuthorizationFilter, error in UsernamePasswordAuthenticationToken usernamePAT = TokenUtils.getAuthentication(token)
package com.XX.ZZ.security;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
#Component
public class JWTAuthorizationFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
String bearerToken = request.getHeader("Authorization");
if(bearerToken != null && bearerToken.startsWith("Bearer ")){
String token = bearerToken.replace("Bearer ", "");
UsernamePasswordAuthenticationToken usernamePAT = TokenUtils.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(usernamePAT);
}
filterChain.doFilter(request, response);
}
}
JwtAuthenticationFilter, error in String token = TokenUtils.createToken
package com.XX.ZZ.security;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import java.io.IOException;
import java.util.Collections;
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
#Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
AuthCredentials authCredentials = new AuthCredentials();
try {
authCredentials = new ObjectMapper().readValue(request.getReader(), AuthCredentials.class);
} catch (IOException e){ }
UsernamePasswordAuthenticationToken usernamePAT = new UsernamePasswordAuthenticationToken(
authCredentials.getEmail(),
authCredentials.getPassword(),
Collections.emptyList()
);
return getAuthenticationManager().authenticate(usernamePAT);
}
#Override
protected void successfulAuthentication(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain,
Authentication authResult) throws IOException, ServletException {
UserDetailsImpl userDetails = (UserDetailsImpl) authResult.getPrincipal();
String token = TokenUtils.createToken(userDetails.getName(), userDetails.getUsername());
response.addHeader("Authorization", "Bearer " + token);
response.getWriter().flush();
super.successfulAuthentication(request, response, chain, authResult);
}
}
By calling it as TokenUtils.getAuthentication(token) you are literally calling it as as if it is a static. You need an instance in JWTAuthenticationFilter:
TokenUtils tokenUtilsInstance = new TokenUtils("my secret");
tokenUtilsInstance.getAuthentication(token)
You probably need to drop the constructor TokenUtils(String jwtSecret). That will allow the following in JWTAuthenticationFilter. Much better Spring practice.
#Autowired
TokenUtils tokenUtilsInstance;
I would like to generate the token for login using springboot, The token is generating while checking using postman, but I am getting null in console
Authenticate controller
package com.demo.grocery.controller;
import com.demo.grocery.config.JwtUtils;
import com.demo.grocery.model.JwtRequest;
import com.demo.grocery.model.JwtResponse;
import com.demo.grocery.model.User;
import com.demo.grocery.service.impl.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.web.bind.annotation.*;
import java.security.Principal;
#RestController
public class AuthenticateController {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private UserDetailsServiceImpl userDetailsServiceImpl;
#Autowired
private JwtUtils jwtUtils;
//generate token
#CrossOrigin("http://localhost:4200")
#PostMapping("/generate-token")
public ResponseEntity<?> generateToken(#RequestBody JwtRequest jwtRequest) throws Exception
{
try {
this.authenticate(jwtRequest.getUsername(), jwtRequest.getPassword());
} catch (UsernameNotFoundException e) {
// TODO: handle exception
e.printStackTrace();
throw new Exception("User Not Found");
}
////////////authenticate
UserDetails userDetails = this.userDetailsServiceImpl.loadUserByUsername(jwtRequest.getUsername());
String token = this.jwtUtils.generateToken(userDetails);
return ResponseEntity.ok(new JwtResponse(token));
}
private void authenticate(String username, String password) throws Exception
{
try {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
} catch (DisabledException e) {
e.printStackTrace();
throw new Exception("USER DISABLED "+e.getMessage());
}
catch(BadCredentialsException e)
{
throw new Exception("Invalid Credentials "+e.getMessage());
}
}
//returns the details of current logged in user
#CrossOrigin("http://localhost:4200")
#GetMapping("/current-user")
public User getCurrentUser(Principal principal)
{
return (User) this.userDetailsServiceImpl.loadUserByUsername(principal.getName());
}
}
JwtAuthenticationFilter
package com.demo.grocery.config;
import com.demo.grocery.service.impl.UserDetailsServiceImpl;
import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
#Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
#Autowired
private UserDetailsServiceImpl userDetailsService;
#Autowired
private JwtUtils jwtUtil;
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
final String requestTokenHeader = request.getHeader("Authorization");
System.out.println(requestTokenHeader);
String username = null;
String jwtToken = null;
if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
// yes
jwtToken = requestTokenHeader.substring(7);
try {
username = this.jwtUtil.extractUsername(jwtToken);
} catch (ExpiredJwtException e) {
e.printStackTrace();
System.out.println("jwt token has expired..");
}
catch (Exception e) {
e.printStackTrace();
System.out.println("error");
}
}
else {
System.out.println("Invalid Token, Not Starts with bearer String");
}
//validate Token
if(username!=null && SecurityContextHolder.getContext().getAuthentication() == null)
{
final UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
if(this.jwtUtil.validateToken(jwtToken, userDetails))
{
//token is valid
UsernamePasswordAuthenticationToken usernamePasswordAuthentication = new UsernamePasswordAuthenticationToken(userDetails,null,userDetails.getAuthorities());
usernamePasswordAuthentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthentication);
}
else
{
System.out.println("Token is not Valid");
}
}
filterChain.doFilter(request, response);
}
}
Service
package com.demo.grocery.service.impl;
import com.demo.grocery.model.User;
import com.demo.grocery.repository.UserRepo;
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;
#Service
public class UserDetailsServiceImpl implements UserDetailsService {
#Autowired
private UserRepo userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = this.userRepository.findByUsername(username);
if (user == null) {
System.out.println("User Not Found");
throw new UsernameNotFoundException("No User Found!!");
}
return user;
}
}
Output in intelliji
Postman output
Look into the screenshots and help me to solve the issue. Why it is storing as null?
For your method to work you should pass your JWT in Postman using Authorization -> Type: Bearer Token.
As you can see in your console log, there's a message "Invalid Token, Not Starts with bearer String", which is printed from your JwtAuthenticationFilter when there's no Authorization header or it doesn't start with "Bearer".
At this point your user is not authenticated, so there's no Principal object in SecurityContextHolder when controller method is executed.
For these cases you should convert response to 401 UNAUTHORIZED status. For example, you can do it in your filter by writing straight to response.
But implementing your own security mechanism is considered a bad practice. I advise to use spring-security build-in JWT-support, which will automatically respond with 401 when there's no valid token found in Authorization header and will store additional info about missing or invalid token at response WWW-Authenticate header.
Take a look at spring-security official sample of jwt-secured resource-server.
I am implementing OAuth2 using spring boot. And followed this example for the same
Spring-oauth2-jpa-example
Video Tutorial
After implementing I have successfully able to generate access token. But the problem is when I try to access protected resource in my case /api. I am getting 404 not found.
Main Method
package com.gatimaanBoot;
import java.util.Arrays;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import com.gatimaanBoot.security.UserRepository;
#SpringBootApplication
public class GatimaanBootApplication {
#Autowired
private PasswordEncoder passwordEncoder;
public static void main(String[] args) {
System.out.println("booting....");
SpringApplication.run(GatimaanBootApplication.class, args);
}
/* #Bean
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
return args -> {
System.out.println("Let's inspect the beans provided by Spring Boot:");
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
//System.out.println(beanName);
}
};
}*/
/**
* Password grants are switched on by injecting an AuthenticationManager.
* Here, we setup the builder so that the userDetailsService is the one we coded.
* #param builder
* #param repository
* #throws Exception
*/
#Autowired
public void authenticationManager(AuthenticationManagerBuilder builder, UserRepository repository, com.gatimaanBoot.security.service.UserService service) throws Exception {
//Setup a default user if db is empty
if (repository.count()==0)
service.save(new com.gatimaanBoot.security.entities.User("user", "user", Arrays.asList(new com.gatimaanBoot.security.entities.Role("USER"), new com.gatimaanBoot.security.entities.Role("ACTUATOR"))));
builder.userDetailsService(userDetailsService(repository)).passwordEncoder(passwordEncoder);
}
/**
* We return an instance of our CustomUserDetails.
* #param repository
* #return
*/
private UserDetailsService userDetailsService(final UserRepository repository) {
return username -> new CustomUserDetails(repository.findByUsername(username));
}
}
AuthorizationServer
/**
* Copyright 2017 Duronto Technology (P) Limited . All Rights Reserved.
* Duronto Technology PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package com.gatimaanBoot.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
/**
*
* #version 1.0, 09-Jul-2017
* #author Nikhil
*/
/**
* Configures the authorization server.
* The #EnableAuthorizationServer annotation is used to configure the OAuth 2.0 Authorization Server mechanism,
* together with any #Beans that implement AuthorizationServerConfigurer (there is a handy adapter implementation with empty methods).
*/
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private PasswordEncoder passwordEncoder;
/**
* Setting up the endpointsconfigurer authentication manager.
* The AuthorizationServerEndpointsConfigurer defines the authorization and token endpoints and the token services.
* #param endpoints
* #throws Exception
*/
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}
/**
* Setting up the clients with a clientId, a clientSecret, a scope, the grant types and the authorities.
* #param clients
* #throws Exception
*/
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory().withClient("my-trusted-client")
.authorizedGrantTypes("password","authorization_code","implicit")
.authorities("ROLE_CLIENT","ROLE_TRUSTED_CLIENT").scopes("read","write","trust")
.resourceIds("oauth2-resource").accessTokenValiditySeconds(5000).secret("secret");
}
/**
* We here defines the security constraints on the token endpoint.
* We set it up to isAuthenticated, which returns true if the user is not anonymous
* #param security the AuthorizationServerSecurityConfigurer.
* #throws Exception
*/
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}
}
ResourceServer
package com.gatimaanBoot.security;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.headers().frameOptions().disable().and()
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/api/**").authenticated();
}
}
Application.properties
#Application Path
server.contextPath = /gatimaanBoot
security.oauth2.resource.filter-order = 3
# Database
spring.datasource.driver = com.mysql.jdbc.Driver
spring.datasource.url = jdbc:mysql://localhost:3306/train?zeroDateTimeBehavior=convertToNull
spring.datasource.username = root
spring.datasource.password = root
# Hibernate
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQLDialect
spring.jpa.properties.hibernate.show_sql= true
spring.jpa.properties.hibernate.hbm2ddl.auto= update
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
Controller
/**
* Copyright 2017 Duronto Technology (P) Limited . All Rights Reserved.
* Duronto Technology PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
package com.gatimaanBoot.station.controller;
/**
*
* #version 1.0, 24-Feb-2017
* #author Deepak Bisht
* #author Nikhil Mishra
*
*
*/
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.gatimaanBoot.station.dto.StationResponseDTO;
import com.gatimaanBoot.station.model.Station;
import com.gatimaanBoot.station.services.StationService;
#Controller
#RequestMapping("/api/")
public class StationController {
private static final Logger LOGGER = LoggerFactory.getLogger(StationController.class);
#Autowired
StationService stationService;
// get data for particular station
#RequestMapping(value = "/v1.0/station/{stationCode}/", method = RequestMethod.GET)
public #ResponseBody Station getStation(#PathVariable String stationCode) {
Station station = null;
try {
station = stationService.getStation(stationCode);
} catch (Exception e) {
e.printStackTrace();
}
return station;
}
/* Getting List of stations in Json format in pagination */
#RequestMapping(value = "/v1.0/station/", method = RequestMethod.GET)
public #ResponseBody List<Station> getStationList(
#RequestParam(value = "page", required = false, defaultValue = "0") int page) {
List<Station> stationList = null;
try {
stationList = stationService.getStationList(page);
} catch (Exception e) {
LOGGER.debug("Station Controller : " + e.getMessage());
e.printStackTrace();
}
return stationList;
}
// insert new station
#RequestMapping(value = "/v1.0/station/", method = RequestMethod.POST)
public #ResponseBody StationResponseDTO insertStation(#RequestBody Station station) {
StationResponseDTO stationDTO = null;
try {
stationDTO = stationService.insertStation(station);
} catch (Exception e) {
e.printStackTrace();
}
return stationDTO;
}
// insert new station
#RequestMapping(value = "/v1.0/station/", method = RequestMethod.PUT)
public #ResponseBody StationResponseDTO updateStation(#RequestBody Station station) {
StationResponseDTO stationDTO = null;
try {
stationDTO = stationService.updateStation(station);
} catch (Exception e) {
e.printStackTrace();
}
return stationDTO;
}
// delete a station
#RequestMapping(value = "/v1.0/station/", method = RequestMethod.DELETE)
public #ResponseBody StationResponseDTO deleteStation(#RequestBody Station station) {
StationResponseDTO stationDTO = null;
try {
stationDTO = stationService.deleteStation(station);
} catch (Exception e) {
e.printStackTrace();
}
return stationDTO;
}
#RequestMapping(value = "/v1.0/station/list/", method = RequestMethod.POST)
public #ResponseBody List<Station> getTrainList(#RequestBody ArrayList<String> stationList) {
return stationService.getStationListBulk(stationList);
}
}
Thanks.
I am using spring security in my spring boot application. Currently we have option to generate token using username and password. Now i need to modify the options like i want username as email and password as mobile number. Is it possible to use like this.
Yes, you have an option for use custom values. For example check the below code,
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
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 sunbox.dao.IUserDAO;
import java.util.ArrayList;
import java.util.List;
#Service
public class CustomUserDetailsService implements UserDetailsService {
#Autowired
private IUserDAO iuserDAO;
#Autowired
public CustomUserDetailsService(IUserDAO iuserDAO) {
this.iuserDAO = iuserDAO;
}
#SuppressWarnings({ "rawtypes", "unchecked" })
#Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
sunbox.domain.User usr = iuserDAO.getUserByEmail(s);
if (usr == null) {
throw new UsernameNotFoundException("User details not found with this username: " + s);
}
String username = usr.getEmail();
String password = usr.getMobile();
String role = usr.getUserType().getUserTypeName();
List authList = getAuthorities(role);
User user = new User(username, password, authList);
return user;
}
#SuppressWarnings({ "rawtypes", "unchecked" })
private List getAuthorities(String role) {
List authList = new ArrayList();
authList.add(new SimpleGrantedAuthority("ROLE_USER"));
if (role != null && role.trim().length() > 0) {
if (role.equals("admin")) {
authList.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
}
}
return authList;
}
}
I am relatively new to Spring and Spring security.
I was attempting to write a program where I needed to authenticate a user at the server end using Spring security,
I came up with the following:
public class CustomAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider{
#Override
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken)
throws AuthenticationException
{
System.out.println("Method invoked : additionalAuthenticationChecks isAuthenticated ? :"+usernamePasswordAuthenticationToken.isAuthenticated());
}
#Override
protected UserDetails retrieveUser(String username,UsernamePasswordAuthenticationToken authentication) throws AuthenticationException
{
System.out.println("Method invoked : retrieveUser");
//so far so good, i can authenticate user here, and throw exception if not authenticated!!
//THIS IS WHERE I WANT TO ACCESS SESSION OBJECT
}
}
My usecase is that when a user is authenticated, I need to place an attribute like:
session.setAttribute("userObject", myUserObject);
myUserObject is an object of some class that I can access throughout my server code across multiple user requests.
Your friend here is org.springframework.web.context.request.RequestContextHolder
// example usage
public static HttpSession session() {
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
return attr.getRequest().getSession(true); // true == allow create
}
This will be populated by the standard spring mvc dispatch servlet, but if you are using a different web framework you have add org.springframework.web.filter.RequestContextFilter as a filter in your web.xml to manage the holder.
EDIT: just as a side issue what are you actually trying to do, I'm not sure you should need access to the HttpSession in the retieveUser method of a UserDetailsService. Spring security will put the UserDetails object in the session for you any how. It can be retrieved by accessing the SecurityContextHolder:
public static UserDetails currentUserDetails(){
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication authentication = securityContext.getAuthentication();
if (authentication != null) {
Object principal = authentication.getPrincipal();
return principal instanceof UserDetails ? (UserDetails) principal : null;
}
return null;
}
Since you're using Spring, stick with Spring, don't hack it yourself like the other post posits.
The Spring manual says:
You shouldn't interact directly with the HttpSession for security
purposes. There is simply no justification for doing so - always use
the SecurityContextHolder instead.
The suggested best practice for accessing the session is:
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
String username = ((UserDetails)principal).getUsername();
} else {
String username = principal.toString();
}
The key here is that Spring and Spring Security do all sorts of great stuff for you like Session Fixation Prevention. These things assume that you're using the Spring framework as it was designed to be used. So, in your servlet, make it context aware and access the session like the above example.
If you just need to stash some data in the session scope, try creating some session scoped bean like this example and let autowire do its magic. :)
i made my own utils. it is handy. :)
package samples.utils;
import java.util.Arrays;
import java.util.Collection;
import java.util.Locale;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.MessageSource;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.ui.context.Theme;
import org.springframework.util.ClassUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.ThemeResolver;
import org.springframework.web.servlet.support.RequestContextUtils;
/**
* SpringMVC通用工具
*
* #author 应卓(yingzhor#gmail.com)
*
*/
public final class WebContextHolder {
private static final Logger LOGGER = LoggerFactory.getLogger(WebContextHolder.class);
private static WebContextHolder INSTANCE = new WebContextHolder();
public WebContextHolder get() {
return INSTANCE;
}
private WebContextHolder() {
super();
}
// --------------------------------------------------------------------------------------------------------------
public HttpServletRequest getRequest() {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
return attributes.getRequest();
}
public HttpSession getSession() {
return getSession(true);
}
public HttpSession getSession(boolean create) {
return getRequest().getSession(create);
}
public String getSessionId() {
return getSession().getId();
}
public ServletContext getServletContext() {
return getSession().getServletContext(); // servlet2.3
}
public Locale getLocale() {
return RequestContextUtils.getLocale(getRequest());
}
public Theme getTheme() {
return RequestContextUtils.getTheme(getRequest());
}
public ApplicationContext getApplicationContext() {
return WebApplicationContextUtils.getWebApplicationContext(getServletContext());
}
public ApplicationEventPublisher getApplicationEventPublisher() {
return (ApplicationEventPublisher) getApplicationContext();
}
public LocaleResolver getLocaleResolver() {
return RequestContextUtils.getLocaleResolver(getRequest());
}
public ThemeResolver getThemeResolver() {
return RequestContextUtils.getThemeResolver(getRequest());
}
public ResourceLoader getResourceLoader() {
return (ResourceLoader) getApplicationContext();
}
public ResourcePatternResolver getResourcePatternResolver() {
return (ResourcePatternResolver) getApplicationContext();
}
public MessageSource getMessageSource() {
return (MessageSource) getApplicationContext();
}
public ConversionService getConversionService() {
return getBeanFromApplicationContext(ConversionService.class);
}
public DataSource getDataSource() {
return getBeanFromApplicationContext(DataSource.class);
}
public Collection<String> getActiveProfiles() {
return Arrays.asList(getApplicationContext().getEnvironment().getActiveProfiles());
}
public ClassLoader getBeanClassLoader() {
return ClassUtils.getDefaultClassLoader();
}
private <T> T getBeanFromApplicationContext(Class<T> requiredType) {
try {
return getApplicationContext().getBean(requiredType);
} catch (NoUniqueBeanDefinitionException e) {
LOGGER.error(e.getMessage(), e);
throw e;
} catch (NoSuchBeanDefinitionException e) {
LOGGER.warn(e.getMessage());
return null;
}
}
}
Indeed you can access the information from the session even when the session is being destroyed on an HttpSessionLisener by doing:
public void sessionDestroyed(HttpSessionEvent hse) {
SecurityContextImpl sci = (SecurityContextImpl) hse.getSession().getAttribute("SPRING_SECURITY_CONTEXT");
// be sure to check is not null since for users who just get into the home page but never get authenticated it will be
if (sci != null) {
UserDetails cud = (UserDetails) sci.getAuthentication().getPrincipal();
// do whatever you need here with the UserDetails
}
}
or you could also access the information anywhere you have the HttpSession object available like:
SecurityContextImpl sci = (SecurityContextImpl) session().getAttribute("SPRING_SECURITY_CONTEXT");
the last assuming you have something like:
HttpSession sesssion = ...; // can come from request.getSession(false);
I try with next code and work excellent
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* Created by jaime on 14/01/15.
*/
#Controller
public class obteinUserSession {
#RequestMapping(value = "/loginds", method = RequestMethod.GET)
public String UserSession(ModelMap modelMap) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String name = auth.getName();
modelMap.addAttribute("username", name);
return "hellos " + name;
}
In my scenario, I've injected the HttpSession into the CustomAuthenticationProvider class
like this
public class CustomAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider{
#Autowired
private HttpSession httpSession;
#Override
protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken)
throws AuthenticationException
{
System.out.println("Method invoked : additionalAuthenticationChecks isAuthenticated ? :"+usernamePasswordAuthenticationToken.isAuthenticated());
}
#Override
protected UserDetails retrieveUser(String username,UsernamePasswordAuthenticationToken authentication) throws AuthenticationException
{
System.out.println("Method invoked : retrieveUser");
//so far so good, i can authenticate user here, and throw exception
if not authenticated!!
//THIS IS WHERE I WANT TO ACCESS SESSION OBJECT
httpSession.setAttribute("userObject", myUserObject);
}
}
If all that you need is details of User, for Spring Version 4.x you can use #AuthenticationPrincipal and #EnableWebSecurity tag provided by Spring as shown below.
Security Configuration Class:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
...
}
Controller method:
#RequestMapping("/messages/inbox")
public ModelAndView findMessagesForUser(#AuthenticationPrincipal User user) {
...
}
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
attr.getSessionId();