Spring security: Read jwt details - spring

I'm receiving a jwt after a call to /login:
ResponseEntity<Void> responseEntity = restTemplate
.postForEntity(url, entity, Void.class);
String bearer = responseEntity
.getHeaders()
.get("Authorization")
.stream().findFirst().get();
After that, I'm getting a jwt token on Authorization header like:
"Bearer eyJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE1Mzg1NjExNDgsInN1YiI6ImFkbWluIiwiZXhwIjoxNTM5NDI1MTQ4fQ.mr4MdNzNC8h1uq-OF9DeEBGS8AFgkN6ysooptNrvJeyyn6L6TLV1W4hv6osMggNpo_Ee6RqBhwuJu1beA8OFoA"
I would like to read expiration date and other information related with it.
Is there any library to handle it?
Does Spring provide any Helper to treat it?
Obviously, I've the secret key.

You can use jwt library to parse the jwt token you received.
For example, I am using jsonwebtoken to parse the token. Something
like this;
public Claims getClaimsFromToken(String token) throws Exception {
Claims claims;
claims = Jwts.parser()
.setSigningKey(SECRET)
.parseClaimsJws(token)
.getBody();
return claims;
}
If you want to get the value of a specific key inside your claims, you
can do it like this;
public Object getClaimsValueFromToken(String token, String key) throws Exception {
Claims claims = getClaimsFromToken(token);
Object value = claims.get(key);
return value;
}
Ideally, you can create your own custom util using jwt library to
be used for parsing the token.
Don't forget also to add the library as a maven dependency;
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.6.0</version>
</dependency>

here is the code sample from my project;
static final String CLAIM_KEY_USERNAME = "sub";
static final String CLAIM_KEY_AUDIENCE = "audience";
static final String CLAIM_KEY_CREATED = "created";
private static final String AUDIENCE_UNKNOWN = "unknown";
private static final String AUDIENCE_WEB = "web";
private static final String AUDIENCE_MOBILE = "mobile";
private static final String AUDIENCE_TABLET = "tablet";
#Value("${jwt.secret}")
private String secret;
#Value("${jwt.expiration}")
private Long expiration;
public String getUsernameFromToken(String token) {
final Claims claims = getClaimsFromToken(token);
return claims != null ? claims.getSubject() : null;
}
public Date getCreatedDateFromToken(String token) {
final Claims claims = getClaimsFromToken(token);
return claims != null ? new Date((Long) claims.get(CLAIM_KEY_CREATED)) : null;
}
public Date getExpirationDateFromToken(String token) {
final Claims claims = getClaimsFromToken(token);
return claims != null ? claims.getExpiration() : null;
}
public String getAudienceFromToken(String token) {
final Claims claims = getClaimsFromToken(token);
return claims != null ? (String) claims.get(CLAIM_KEY_AUDIENCE) : null;
}
private Claims getClaimsFromToken(String token) {
return StringUtils.hasText(token) ? Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody() : null;
}
private Date generateExpirationDate() {
return new Date(System.currentTimeMillis() + expiration * 1000);
}
private Boolean isTokenExpired(String token) {
final Date expirationDate = getExpirationDateFromToken(token);
return expirationDate.before(new Date());
}
private Boolean isCreatedBeforeLastPasswordReset(Date created, Date lastPasswordReset) {
return (lastPasswordReset != null && created.before(lastPasswordReset));
}
private String generateAudience(Device device) {
String audience = AUDIENCE_UNKNOWN;
if (device.isNormal()) {
audience = AUDIENCE_WEB;
} else if (device.isTablet()) {
audience = AUDIENCE_TABLET;
} else if (device.isMobile()) {
audience = AUDIENCE_MOBILE;
}
return audience;
}
private Boolean ignoreTokenExpiration(String token) {
String audience = getAudienceFromToken(token);
return (AUDIENCE_TABLET.equals(audience) || AUDIENCE_MOBILE.equals(audience));
}
public String generateToken(UserDetails userDetails, Device device) {
Map<String, Object> claims = new HashMap<>();
claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());
claims.put(CLAIM_KEY_AUDIENCE, generateAudience(device));
claims.put(CLAIM_KEY_CREATED, new Date());
return generateToken(claims);
}
String generateToken(Map<String, Object> claims) {
return Jwts.builder().setClaims(claims).setExpiration(generateExpirationDate()).signWith(SignatureAlgorithm.HS512, secret).compact();
}
public Boolean canTokenBeRefreshed(String token, Date lastPasswordReset) {
final Date created = getCreatedDateFromToken(token);
return !isCreatedBeforeLastPasswordReset(created, lastPasswordReset) && (!isTokenExpired(token) || ignoreTokenExpiration(token));
}
public String refreshToken(String token) {
String refreshedToken;
try {
final Claims claims = getClaimsFromToken(token);
claims.put(CLAIM_KEY_CREATED, new Date());
refreshedToken = generateToken(claims);
} catch (Exception e) {
refreshedToken = null;
}
return refreshedToken;
}
public Boolean validateToken(String token, UserDetails userDetails) {
JwtUser user = (JwtUser) userDetails;
final String username = getUsernameFromToken(token);
final Date created = getCreatedDateFromToken(token);
return (username.equals(user.getUsername()) && !isTokenExpired(token) && !isCreatedBeforeLastPasswordReset(created, user.getLastPasswordResetDate()));
}

Related

Get actual user details with spring boot

Actually I´m working in a forum project built with Spring boot, Mongodb and Vue.js.
When I´m trying to post a new comment and get the user datails with the SecurityContextHolder and cast it to my UsersDetailImpl who implements from the UserDetails class provided by Spring boot, it throw the following error: org.springframework.security.web.authentication.webauthenticationdetails cannot be cast to .... UserDetailsImpl
I don´t really know the reason of this error becasuse if I test it from Postman does not report an error.
UserDetailsImpl.java
public class UserDetailsImpl implements UserDetails {
private static final long serialVersionUID = 1L;
private String id;
private String username;
private String email;
#JsonIgnore
private String password;
private Collection<? extends GrantedAuthority> authorities;
public UserDetailsImpl(String id, String username, String email, String password,
Collection<? extends GrantedAuthority> authorities) {
this.id = id;
this.username = username;
this.email = email;
this.password = password;
this.authorities = authorities;
}
public static UserDetailsImpl build(User user) {
List<GrantedAuthority> authorities = user.getRoles().stream()
.map(role -> new SimpleGrantedAuthority(role.getName().name()))
.collect(Collectors.toList());
return new UserDetailsImpl(
user.getId(),
user.getUsername(),
user.getEmail(),
user.getPassword(),
authorities);
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
public String getId() {
return id;
}
public String getEmail() {
return email;
}
#Override
public String getPassword() {
return password;
}
#Override
public String getUsername() {
return username;
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
#Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
UserDetailsImpl user = (UserDetailsImpl) o;
return Objects.equals(id, user.id);
}
}
CommentController.java
#CrossOrigin(origins = "*", maxAge = 3600)
#RestController
#RequestMapping("/comments")
public class CommentController {
#Autowired
CommentRepository commentRepository;
#Autowired
RoleRepository roleRepository;
#PostMapping("/ask")
public ResponseEntity<?> ask (#Valid #RequestBody AskRequest askRequest) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
HashSet<String> strRoles = userDetails.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toCollection(HashSet::new));
Set<Role> roles = new HashSet<>();
strRoles.forEach(role -> {
int cutPoint = role.indexOf("_");
role = role.substring(cutPoint + 1).toLowerCase();
findRole(roles, role, roleRepository);
});
User user = new User(userDetails.getUsername(), userDetails.getEmail(), roles);
ObjectId discussion_id = ObjectId.get();
String slug = new Slugify().slugify(askRequest.getTitle());
Comment comment = new Comment(discussion_id, askRequest.getTitle(),
askRequest.getText(),slug, "full_slug_test", Instant.now(),user);
String info = comment.getDiscussion_id().toString() + comment.getPosted() + comment.getTitle()
+ comment.getText() + comment.getAuthor().getUsername() + comment.getAuthor().getEmail()
+ comment.getAuthor().getId() + comment.getAuthor().getRoles();
commentRepository.save(comment);
return ResponseEntity.ok(new MessageResponse(info));
}
}
I´m new in all this technologies there may be serious errors. All the advices will be a great help to me because the project is academic.
If someone need more information just ask for it.
Thank you all :)
Change authentication.getDetails() to getAuthentication().getPrincipal()
You will have:
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
Finally I found the error and it was in the front-end side. I was sending de headers with the JWT in this way.
import axios from 'axios';
import authHeader from './auth-header';
const API_URL = 'http://localhost:8080/comments/';
class CommentsService {
ask(post){
return axios.post(API_URL + 'ask', {
title: post.title,
text: post.text,
headers: authHeader()
});
}
}
export default new CommentsService();
and it is totally wrong so I found the manner to do it.
import axios from 'axios';
import authHeader from './auth-header';
const API_URL = 'http://localhost:8080/comments/';
class CommentsService {
ask(post){
return axios.post(API_URL + 'ask', {
title: post.title,
text: post.text
},{headers: authHeader()});
}
}
export default new CommentsService();
I also add the code to mount the headers.
export default function authHeader() {
let user = JSON.parse(localStorage.getItem('user'));
if (user && user.accessToken) {
return { Authorization: 'Bearer ' + user.accessToken };
} else {
return {};
}
}

'%X{value}' is not working in log4J print

Following an this code, im using MDC in order to have a unique ID per each request in my Spring-Boot application:
Slf4jMDCFilterConfiguration.java
#Data
#Configuration
public class Slf4jMDCFilterConfiguration {
public static final String DEFAULT_RESPONSE_TOKEN_HEADER = "Response_Token";
public static final String DEFAULT_MDC_UUID_TOKEN_KEY = "Slf4jMDCFilter.UUID";
public static final String DEFAULT_MDC_CLIENT_IP_KEY = "Slf4jMDCFilter.ClientIP";
private String responseHeader = DEFAULT_RESPONSE_TOKEN_HEADER;
private String mdcTokenKey = DEFAULT_MDC_UUID_TOKEN_KEY;
private String mdcClientIpKey = DEFAULT_MDC_CLIENT_IP_KEY;
private String requestHeader = null;
#Bean
public FilterRegistrationBean servletRegistrationBean() {
final FilterRegistrationBean registrationBean = new FilterRegistrationBean();
final Slf4jMDCFilter log4jMDCFilterFilter = new Slf4jMDCFilter(responseHeader, mdcTokenKey, mdcClientIpKey, requestHeader);
registrationBean.setFilter(log4jMDCFilterFilter);
registrationBean.setOrder(2);
return registrationBean;
}
}
Slf4jMDCFilter.java
#Data
#EqualsAndHashCode(callSuper = false)
#Component
public class Slf4jMDCFilter extends OncePerRequestFilter {
private final Logger log = Logger.getLogger(getClass());
private final String responseHeader;
private final String mdcTokenKey;
private final String mdcClientIpKey;
private final String requestHeader;
public Slf4jMDCFilter() {
responseHeader = Slf4jMDCFilterConfiguration.DEFAULT_RESPONSE_TOKEN_HEADER;
mdcTokenKey = Slf4jMDCFilterConfiguration.DEFAULT_MDC_UUID_TOKEN_KEY;
mdcClientIpKey = Slf4jMDCFilterConfiguration.DEFAULT_MDC_CLIENT_IP_KEY;
requestHeader = null;
}
public Slf4jMDCFilter(final String responseHeader, final String mdcTokenKey, final String mdcClientIPKey, final String requestHeader) {
this.responseHeader = responseHeader;
this.mdcTokenKey = mdcTokenKey;
this.mdcClientIpKey = mdcClientIPKey;
this.requestHeader = requestHeader;
}
#Override
protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain)
throws java.io.IOException, ServletException {
try {
final String token = extractToken(request);
final String clientIP = extractClientIP(request);
MDC.put(mdcClientIpKey, clientIP);
MDC.put(mdcTokenKey, token);
if (!StringUtils.isEmpty(responseHeader)) {
response.addHeader(responseHeader, token);
}
chain.doFilter(request, response);
} finally {
MDC.remove(mdcTokenKey);
MDC.remove(mdcClientIpKey);
}
}
private String extractToken(final HttpServletRequest request) {
final String token;
if (!StringUtils.isEmpty(requestHeader) && !StringUtils.isEmpty(request.getHeader(requestHeader))) {
token = request.getHeader(requestHeader);
} else {
token = UUID.randomUUID().toString().toUpperCase().replace("-", "");
}
return token;
}
private String extractClientIP(final HttpServletRequest request) {
final String clientIP;
if (request.getHeader("X-Forwarded-For") != null) {
clientIP = request.getHeader("X-Forwarded-For").split(",")[0];
} else {
clientIP = request.getRemoteAddr();
}
return clientIP;
}
#Override
protected boolean isAsyncDispatch(final HttpServletRequest request) {
return false;
}
#Override
protected boolean shouldNotFilterErrorDispatch() {
return false;
}
}
log4j.properties
# Define the properties for file appender
log4j.appender.FILE.layout.conversionPattern=%X{Slf4jMDCFilter.UUID}|[%d{ISO8601}][%p][%t] %C{1} %x - %m%n
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
log4j.appender.FILE.File=logs/AmericanWell-FRE.log
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.MaxFileSize=20MB
log4j.appender.FILE.MaxBackupIndex=20
log4j.appender.FILE.append=true
log4j.rootCategory=ALL, rollingFile
#CONSOLE Settings
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.conversionPattern=%X{Slf4jMDCFilter.UUID}|[%d{ISO8601}][%p][%t] %C{1} %x - %m%n
My problem is when i'm trying to use %X{Slf4jMDCFilter.UUID}, in the log file and console i'm getting empty string.
Here's a sample output of my log - the token is being generated but the value is not printed:
|[2019-05-28 14:09:38,919][INFO][http-nio-8080-exec-1] Slf4jMDCFilter - 0******************************************************************************* token = null
|[2019-05-28 14:09:38,921][INFO][http-nio-8080-exec-1] Slf4jMDCFilter - 1******************************************************************************* token = 2A905F87CB84484B8EC05D6432D39303
|[2019-05-28 14:09:38,921][INFO][http-nio-8080-exec-1] Slf4jMDCFilter - 2******************************************************************************* token = 2A905F87CB84484B8EC05D6432D39303
|[2019-05-28 14:09:38,997][INFO][http-nio-8080-exec-1] Slf4jMDCFilter - 3******************************************************************************* token = 2A905F87CB84484B8EC05D6432D39303
|[2019-05-28 14:09:38,998][INFO][http-nio-8080-exec-1] Slf4jMDCFilter - 4******************************************************************************* token = 2A905F87CB84484B8EC05D6432D39303
|[2019-05-28 14:09:38,998][INFO][http-nio-8080-exec-1] Slf4jMDCFilter - 5******************************************************************************* token = null
|[2019-05-28 14:09:38,998][INFO][http-nio-8080-exec-1] Slf4jMDCFilter - 6******************************************************************************* token = null
|[2019-05-28 14:09:38,999][INFO][http-nio-8080-exec-1] Slf4jMDCFilter - 7******************************************************************************* token = null
I tried several ways to print it but nothing was working.
Am I missing some configuration here?
I too encountered this. The issue was that there were multiple MDCs in the project.
I was using org.slf4j.MDC to write the context. The Pattern, which uses %X{varname}, was set to use org.apache.log4j.MDC.
I changed my code to use org.apache.log4j.MDC and all was well.

Getting a NullPointer instead of creating a token

I'm currently writing a Spring Boot application using JWT. Testing the functionality responsible for creating a token using different dates I encountered a problem. Well, instead of a token I get NullPointer. That's how I test it:
#Test
public void testGenerateTokenFromDifferentDates() {
when(clockMock.now())
.thenReturn(DateUtil.yesterday())
.thenReturn(DateUtil.now());
String token = createToken();
String tokenLater = createToken();
assertThat(token).isNotEqualTo(tokenLater);
}
private String createToken() {
String token = tokenUtil.generateToken(new TestUser(USERNAME));
return token;
}
And this is the class responsible for creating the token:
#Component
public class TokenUtil implements Serializable {
private static final long serialVersionUID = -3301605591108950415L;
#Value("${jwt.secret}")
private String secret;
private Clock clock = DefaultClock.INSTANCE;
#Value("${jwt.expires.days}")
private Long expiration;
public String getUsernameFromToken(String token) {
return getClaimsFromToken(token, Claims::getSubject);
}
public <T> T getClaimsFromToken(String token, Function<Claims, T> resolverClaims) {
final Claims claims = getAllClaimsFromToken(token);
return resolverClaims.apply(claims);
}
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return doGenerateToken(claims, userDetails.getUsername());
}
private Claims getAllClaimsFromToken(String token) {
return Jwts.parser().setSigningKey(secret).parseClaimsJwt(token).getBody();
}
private String doGenerateToken(Map<String, Object> claims, String subject) {
final Date createdDate = clock.now();
final Date expirationDate = calculateExpirationDate(createdDate);
return Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setIssuedAt(createdDate)
.setExpiration(expirationDate)
.signWith(SignatureAlgorithm.HS512, this.secret)
.compact();
}
private Date calculateExpirationDate(Date createdDate) {
return new Date(createdDate.getTime() + expiration * 1000);
}
}
I can't think what the reason may be. Debugger also doesn't help me because it doesn't come to this moment. Here is the repository.
As #theonlyrao suggested here is the stack trace:
java.lang.NullPointerException
at com.github.springjwt.security.jwt.TokenUtil.calculateExpirationDate(TokenUtil.java:59)
at com.github.springjwt.security.jwt.TokenUtil.doGenerateToken(TokenUtil.java:47)
at com.github.springjwt.security.jwt.TokenUtil.generateToken(TokenUtil.java:38)
at com.github.springjwt.security.jwt.TokenUtilTest.createToken(TokenUtilTest.java:42)
at com.github.springjwt.security.jwt.TokenUtilTest.testGenerateTokenFromDifferentDates(TokenUtilTest.java:35)
It seems like either createdDate or expiration are null.
I'm not sure how createdDate get instantiated because I've not used that DefaultClock library.
I think the issue with expiration is that you haven't told Spring where to look for the the application properties in your test. Unless that happening elsewhere in code, you need to specific the path to the resource as described in https://www.baeldung.com/spring-classpath-file-access.

Update User's first name and last name in principal

I am updating user's information like first name and last name and I am getting first name and last name in all the pages for welcome message.
I have two controllers one for ajax request mapping and the other for normal request mapping.
Normal request mapping controller have this method. In this controller all page navigation is present and some request mapping which are not ajax calls
private String getPrincipalDisplay() {
GreenBusUser user = null;
String userName = "";
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
user = (GreenBusUser) principal;
userName = user.getFirstName() + " " + user.getLastName();
} else {
userName = "";
}
return userName;
}
This is how I am getting the username on every page by return string of this function I am adding it in ModelMap object.
When I update user's information I am doing in ajax request mapping.
#RequestMapping(value = "/restify/updateUserData", method = RequestMethod.PUT, headers = "Accept=application/json")
public ServiceResponse forgotPassword(#RequestBody Object user)
{
//logger.debug("getting response");
return setDataPut("http://localhost:7020/forgotPassword",user);
}
user is an Object type which has json data. Now how do I retrieve data from object and update my first name and last name in principal.
This is my GreenBusUser class
public class GreenBusUser implements UserDetails
{
private static final long serialVersionUID = 1L;
private String username;
private String password;
private Collection<? extends GrantedAuthority> grantedAuthorities;
private String firstName;
private String lastName;
public GreenBusUser(String username,String password,Collection<? extends GrantedAuthority> authorities,String firstName, String lastName)
{
this.username = username;
this.password = password;
this.grantedAuthorities = authorities;
this.firstName=firstName;
this.lastName=lastName;
this.grantedAuthorities.stream().forEach(System.out::println);
}
public Collection<? extends GrantedAuthority> getAuthorities()
{
return grantedAuthorities;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String getPassword()
{
return password;
}
public String getUsername()
{
return username;
}
public boolean isAccountNonExpired()
{
return true;
}
public boolean isAccountNonLocked()
{
return true;
}
public boolean isCredentialsNonExpired()
{
return true;
}
public boolean isEnabled()
{
return true;
}
}
UPDATE:::::
I have updated your code and applied some part of your answer into mine but still I ran into a problem
#RequestMapping(value="/updateUser",method=RequestMethod.GET)
public String updateUser(ModelMap model) {
UserInfo user = getUserObject();
GreenBusUser newGreenBususer = null;
List<User> list = new ArrayList<User>();
list = FetchDataService.fetchDataUser("http://localhost:8060/GetuserbyUserName?username=" + getPrincipal(), user.getUsername(), user.getPassword());
logger.debug("new user list ----->>>"+list.size());
User newuser=(User)list.get(0);
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
SecurityContextHolder.getContext().getAuthentication().getPrincipal(), SecurityContextHolder.getContext().getAuthentication().getCredentials());
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
newGreenBususer=(GreenBusUser)principal;
logger.debug("newGreenBususerDetails---->>>"+newGreenBususer.toString());
newGreenBususer.setFirstName(newuser.getFirstName());
newGreenBususer.setLastName(newuser.getLastName());
if(newGreenBususer.getFirstName()!=null) {
logger.debug("got my first name");
}
if(newGreenBususer.getLastName()!=null) {
logger.debug("got my last name");
}
auth.setDetails(newGreenBususer);
SecurityContext context = SecurityContextHolder.getContext();
context.setAuthentication(auth);
SecurityContextHolder.setContext(context);
model.addAttribute("user", getPrincipalDisplay());
model.addAttribute("userData", list);
model.addAttribute("check", true);
return "GreenBus_updateProfile_User";
}
At first it sets the firstname and lastname to GreenBusUser and then there is setDetails method when I reload the page it says No user found when I am calling getUserObject() method at the top of this method.
private X2CUser getUserObject() {
X2CUser userName = null;
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
userName = ((X2CUser) principal);
} else {
logger.info("No user found");
}
return userName;
}
If you are updating the password, then it will be good to logout the user and tell him to relogin.
Try this code .. It might help you.
UsernamePasswordAuthenticationToken authReq = new UsernamePasswordAuthenticationToken(user, pass);
Authentication auth = authManager.authenticate(authReq);
SecurityContext sc = SecurityContextHolder.getContext();
securityContext.setAuthentication(auth);
I have finally resolved my problem though I have later added some code in my question part in UPDATE section.
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
newGreenBususer=(GreenBusUser)principal;
newGreenBususer.setFirstName(newuser.getFirstName());
newGreenBususer.setLastName(newuser.getLastName());
Yes that's all need to be done.
This part--->>
auth.setDetails(newGreenBususer);
SecurityContext context = SecurityContextHolder.getContext();
context.setAuthentication(auth);
SecurityContextHolder.setContext(context);
set new context making security pointing to null when I reload still not clear because I am setting the details before reload so its like I get new context but I have set the new user details.
Though I have finally resolved my problem but if anyone could shed some light why it was happening then I will accept his/her answer.
Thanks alot for your support. Keep Learning!

Spring Rest Issue

I am getting an error while i am trying to test my "testCreateUser" method using Spring RestApi, the uploadNewUser.xml contains the login information about the user and the role.
#Test
public void testCreateUser() throws Exception {
Reader reader = getFileReader("src/test/resources/uploadNewUser.xml");
String input_xml = IOUtils.toString(reader);
byte[] content = input_xml.getBytes();
request.addHeader("Accept", "application/xml");
request.addHeader("Content-Type", "application/xml");
request.setContent(content);
request.setContentType("text/xml");
request.setMethod(RequestMethod.POST.name());
request.setRequestURI("/restapi/users/");
final ModelAndView mav = handle(request, response);
Map<String, Object> map = mav.getModel();
for (Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
UserCollection collection = (UserCollection) entry.getValue();
org.springframework.validation.BindingResult.error = com.xxx.dashboard.restapi.GlobalResponse#42a4fd6d
error stack:
java.lang.ClassCastException: com.xxx.dashboard.restapi.GlobalResponse cannot be cast to com.xxx.dashboard.restapi.UserCollection
and i am getting an issue with cannot cast GlobalRespose to UserCollection. can anyone tell me where exactly i am doing is wrong? any help or pointers are most welcome thanks in advance
#Controller("userrestapi")
#RequestMapping(value = { "/restapi/users/", "/restapi/users" })
public class UserRestApi extends AbstractBaseApi {
...
#RequestMapping(method = RequestMethod.POST)
#ResponseStatus(value = HttpStatus.CREATED)
public ModelAndView createNewUser(#RequestBody UserCollection userCollection,
#RequestHeader(value = "accept", required = false) String accept,
#RequestHeader(value = "version", required = false) String version) {
try {
OOUser ooUser = userCollection.getUsers().get(0);
Mapper mapper = (Mapper) userVersions.get(Constants.USER_DETAIL_VERSION_MAPPER_KEY);
int userId = usersRestApiService.validateAndCreateNewUser(ooUser, mapper);
List<FilterField> filterFieldList = new ArrayList<FilterField>();
filterFieldList.add(new FilterField("userId", String.valueOf(userId)));
return getUserDetailsForFilter(filterFieldList, accept, version, mapper);
} catch (Exception ex) {
logger.warn("Api exception", ex);
return getModelAndView(accept, "error", getGlobalResponse(ex));
}
the abstractbaseapi contains following
public class AbstractBaseApi {
public static final String XML_VIEW = "apiXmlView";
public static final String JSON_VIEW = "apiJsonView";
public static final String JSON_ACCEPT_HEADER = "application/json";
public static final String JSON_CONTENT_HEADER = "Content-type: application/json";
public static final String XML_CONTENT_HEADER = "Content-type: text/html;charset=utf-8";
public static final int MAX_COUNT = 100;
public static final String XML_REQUEST_ERROR_FORMAT = "<?xml version='1.0' encoding='UTF-8'?><GlobalResponse xmlns='http://www.operative.com/api' xmlns:v2='http://www.operative.com/api/v2' xmlns:v1='http://www.operative.com/api/v1'> <error errorCode='%1$s' text='%2$s'/> </GlobalResponse>";
public static final String JSON_REQUEST_ERROR_FORMAT = "{error:{errorCode:'%1$s',text:'%2$s'}}";
protected final Logger logger = Logger.getLogger(this.getClass());
protected ModelAndView getModelAndView(String accept, String key, Object value) {
String view = XML_VIEW;
if (accept != null && accept.toLowerCase().contains(JSON_ACCEPT_HEADER)) {
view = JSON_VIEW;
}
if (logger.isDebugEnabled()) {
logger.debug("Accept Header:" + accept + " , generating:" + view);
}
return new ModelAndView(view, BindingResult.MODEL_KEY_PREFIX + key, value);
}
Your model contains more than you think.
You are going through your model and looking for your user collection. However, the first encountered object in your map seems to be the GlobalResponse map.
You should probably just get it by name from the model, i.e.
UserCollection collection = (UserCollection) mav.getModel().get("userCollection");
rather than iterating..

Resources