Trouble with Firefox not sending cookies with ajax call - ajax

Websphere 7
Java 1.7
Jersey 1.19
I have a page which is sending an ajax call to a REST endpoint within the same web application. I have a Filter which sets up the session when the user accesses the page. However, in Firefox, the session is null when I try to access it in the REST endpoint. I am not having this problem with IE10 or Chrome. It seems as though Firefox is not sending the tracking cookie when it makes the AJAX call. That is what I see in Firebug. My Firefox is set to accept cookies.
var firsttest = function() {
return $.ajax({
url: "rest/test/testmethod1",
method: "GET"
});
};
#GET
#Path("/testmethod1")
#Produces(MediaType.APPLICATION_JSON)
public Response testMethod1(#Context HttpServletRequest request) throws JsonGenerationException,
JsonMappingException, IOException {
System.out.println("request = " + request);
if (!isUserReadOnly(request) && !isUserReadWrite(request)) {
return Response.status(Status.FORBIDDEN).build();
}
ObjectMapper mapper = new ObjectMapper();
TestResponse testResponse = new TestResponse(1, "A");
return Response.ok(mapper.writeValueAsString(testResponse)).build();
}
private boolean isUserReadOnly(HttpServletRequest request) {
HttpSession session = request.getSession(false);
Authentication authentication = (Authentication) session.getAttribute("authentication");
if (authentication == null) {
System.out.println("authentication null");
return false;
}
System.out.println(authentication.toString());
return authentication.isReadOnlyRole();
}
private boolean isUserReadWrite(HttpServletRequest request) {
HttpSession session = request.getSession(false);
Authentication authentication = (Authentication) session.getAttribute("authentication");
if (authentication == null) {
System.out.println("authentication null");
return false;
}
System.out.println(authentication.toString());
return authentication.isReadWriteRole();
}

Related

Spring Security: Unable to re-login

I am fixing an existing application, where first login works fine and the logout works fine taking me back to login page.
However after logout, when I try to re-login without browser refresh (just enter credentials on login page), I am getting redirected to Host based URL(which is blocked over the intranet).
Reason
SavedRequest savedRequest = requestCache.getRequest(request, response);
is null during re-login.
I think that may be because I loggedOut, session is cleared by LogoutHandler.
Code for reference.
`public class BroadleafAdminAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
RequestCache requestCache = new HttpSessionRequestCache();
private static final String successUrlParameter = "successUrl=";
private static final String APPLICATIONURL = "APPLICATIONURL";
#Resource(name = "blAdminSecurityRemoteService")
protected SecurityVerifier adminRemoteSecurityService;
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws ServletException, IOException {
AdminUser user = adminRemoteSecurityService.getPersistentAdminUser();
if (user != null && user.getLastUsedSandBoxId() != null) {
request.getSession(false).setAttribute(BroadleafSandBoxResolver.SANDBOX_ID_VAR, user.getLastUsedSandBoxId());
}
SavedRequest savedRequest = requestCache.getRequest(request, response);
if (savedRequest == null) {
super.onAuthenticationSuccess(request, response, authentication);
return;
}
.
String targetUrl = savedRequest.getRedirectUrl();
.
*Logic where I update my targetUrl*
.
getRedirectStrategy().sendRedirect(request, response, targetUrl);
}
}`
I want to avoid going into this condition
if (savedRequest == null) Since I am then unable to execute
*Logic where I update my targetUrl*

Spring Redirect and delete ModelAttribute

I have a controller:
#GetMapping(value = "/login")
public ModelAndView loginGet (#ModelAttribute(value = "MESSAGE_CUSTOM") String message) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || authentication instanceof AnonymousAuthenticationToken) {
return new ModelAndView("/login");
} else {
return new ModelAndView("redirect:/");
}
}
When I do a redirect, in this case the ModelAttribute is redirected too:
http://localhost:8080/?MESSAGE_CUSTOM=
How do I prevent the ModelAttribute from being redirected?
#GetMapping(value = "/login")
public ModelAndView loginGet (#ModelAttribute(value = "MESSAGE_CUSTOM") String message) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || authentication instanceof AnonymousAuthenticationToken) {
return new ModelAndView("/login");
} else {
RedirectView redirectView = new RedirectView("/");
redirectView.setExposeModelAttributes(false);
return new ModelAndView(redirectView);
}
}
http
http://localhost:8080/

Spring Security 5 Stateless OAuth2 Login - how to implement cookies based AuthorizationRequestRepository

I'm trying to have Google/Facebook login using Spring Security 5 OAuth2 login feature. But the problem I'm facing is that I'm coding a stateless API, whereas Spring security 5 uses HttpSessionOAuth2AuthorizationRequestRepository to store authorization requests, which uses session. So, I thought not to use that and code a cookie based implementation, which looks as below:
public class HttpCookieOAuth2AuthorizationRequestRepository implements AuthorizationRequestRepository<OAuth2AuthorizationRequest> {
private static final String COOKIE_NAME = "some-name";
#Override
public OAuth2AuthorizationRequest loadAuthorizationRequest(HttpServletRequest request) {
Assert.notNull(request, "request cannot be null");
return fetchCookie(request)
.map(this::toOAuth2AuthorizationRequest)
.orElse(null);
}
#Override
public void saveAuthorizationRequest(OAuth2AuthorizationRequest authorizationRequest, HttpServletRequest request,
HttpServletResponse response) {
Assert.notNull(request, "request cannot be null");
Assert.notNull(response, "response cannot be null");
if (authorizationRequest == null) {
deleteCookie(request, response);
return;
}
Cookie cookie = new Cookie(COOKIE_NAME, fromAuthorizationRequest(authorizationRequest));
cookie.setPath("/");
cookie.setHttpOnly(true);
response.addCookie(cookie);
}
private String fromAuthorizationRequest(OAuth2AuthorizationRequest authorizationRequest) {
return Base64.getUrlEncoder().encodeToString(
SerializationUtils.serialize(authorizationRequest));
}
private void deleteCookie(HttpServletRequest request, HttpServletResponse response) {
fetchCookie(request).ifPresent(cookie -> {
cookie.setValue("");
cookie.setPath("/");
cookie.setMaxAge(0);
response.addCookie(cookie);
});
}
#Override
public OAuth2AuthorizationRequest removeAuthorizationRequest(HttpServletRequest request) {
// Question: How to remove the cookie, because we don't have access to response object here.
return loadAuthorizationRequest(request);
}
private Optional<Cookie> fetchCookie(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
if (cookies != null && cookies.length > 0)
for (int i = 0; i < cookies.length; i++)
if (cookies[i].getName().equals(COOKIE_NAME))
return Optional.of(cookies[i]);
return Optional.empty();
}
private OAuth2AuthorizationRequest toOAuth2AuthorizationRequest(Cookie cookie) {
return SerializationUtils.deserialize(
Base64.getUrlDecoder().decode(cookie.getValue()));
}
}
The above basically stores the data in a cookie instead of session. I've a couple of questions:
How exactly to code the removeAuthorizationRequest method above? I wanted the cookie removed there, but we don't have access to the response object.
Does the above (cookie based) approach look okay? E.g. any security issues?
Update: Have created an issue at https://github.com/spring-projects/spring-security/issues/5313 . Until that's addressed, here is a workaround I came up with: https://www.naturalprogrammer.com/blog/1681261/spring-security-5-oauth2-login-signup-stateless-restful-web-services

Spring Boot rendering index page after authentication

I have implemented SSO SAML using Spring Security. In my Spring Boot project I have the following controller which basically redirects a user to an idP login page it then generates a JWT token based on a successful login. This JWT token is then forwarded to the index page as a header. But I cant seem to get this to work properly.
Auth Controller,
#Controller
public class AuthController {
private static final Logger log = LoggerFactory.getLogger(UserAccountResource.class);
#Inject
private TokenProvider tokenProvider;
/**
* Given that a user is already authenticated then generate a token
*
* #return the ResponseEntity with status 200 (OK) and with body of the updated {#link JWTToken} jwt token
*/
#RequestMapping(value = "/auth/login")
public String login(HttpServletResponse response) throws Exception {
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
throw new UnauthorizedException();
} else {
try {
final SAMLCredential credential = (SAMLCredential) authentication.getCredentials();
final DateTime dateTime = credential.getAuthenticationAssertion()
.getIssueInstant()
.toDateTime(DateTimeZone.forTimeZone(TimeZone.getDefault()));
String jwt = tokenProvider.createToken(authentication, dateTime.getMillis(), false);
response.addHeader(JWTConfigurer.AUTHORIZATION_HEADER, "Bearer " + jwt);
log.debug("Generated jwt {}", jwt);
log.debug("SAMLCredential {}", credential);
return "forward:/";
} catch (Exception e) {
throw new UnauthorizedException(e);
}
}
}
}
WebMvcConfigurerAdapter is as follows,
#Configuration("webConfigurer")
public class WebConfigurer extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("forward:/index.html");
}
}
As far as SSO via SAML goes everything works great. The user gets redirected to the idP login e.t.c. What I cant figure out is why the forward isn't work as expected.
All my UI (Angular 4.x) is initiated with index.html.
When I tested this I can see it being forwarded to / however no headers come through.
What I did in the end is to separate the login and jwt generation to two APIs calls which worked great.
#GetMapping("/login")
public String samlLogin() throws Exception {
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
throw new UnauthorizedException("Unable to get the SAML authentication information");
} else {
try {
final SAMLCredential credential = (SAMLCredential) authentication.getCredentials();
if (credential == null) {
throw new UnauthorizedException("Not valid SAML credentials");
}
return "forward:/";
} catch (Exception e) {
throw new UnauthorizedException(e);
}
}
}
#GetMapping("/jwt")
public ResponseEntity<String> generateJWT(HttpServletResponse response) throws Exception {
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
throw new UnauthorizedException("Unable to get the SAML authentication information");
} else {
try {
final SAMLCredential credential = (SAMLCredential) authentication.getCredentials();
if (credential == null) {
throw new UnauthorizedException("Not valid SAML credentials");
}
final DateTime dateTime = credential.getAuthenticationAssertion()
.getIssueInstant()
.toDateTime(DateTimeZone.forTimeZone(TimeZone.getDefault()));
String jwt = tokenProvider.createToken(authentication, dateTime.getMillis(), false);
response.addHeader(JWTConfigurer.AUTHORIZATION_HEADER, "Bearer " + jwt);
log.debug("Generated jwt {} for SAML authentication", jwt);
return new ResponseEntity<>(jwt, HttpStatus.OK);
} catch (Exception e) {
throw new UnauthorizedException(e);
}
}
}

How to know that a session is expired?

I set values to the session object in the method of a controller after success of login :
#RequestMapping(value = "/", method = RequestMethod.POST)
public ModelAndView processLogin(Model model, HttpServletRequest request, HttpSession session, #RequestParam String login, #RequestParam String pwd) {
if ( utilisateurDao.verifierLoginUser(login) ) {
if ( utilisateurDao.verifierUser(login, pwd) ) {
HashMap<String, String> criteres = new HashMap<String, String>();
criteres.put("user_login", login);
criteres.put("user_passwd", pwd);
List<Utilisateur> users = utilisateurDao.lireParCritere(criteres);
session.setAttribute("user_code", ((Utilisateur)users.get(0)).getUser_code());
session.setAttribute("menu", menuDao.afficherMenuParUtilisateur((Integer)session.getAttribute("user_code"), env, request, session));
criteres.clear();
users.clear();
criteres.put("user_code", String.valueOf(session.getAttribute("user_code")));
users = utilisateurDao.lireParCritere(criteres);
session.setAttribute("user_names", ((Utilisateur)users.get(0)).getNoms());
session.setAttribute("logout_menu", env.getProperty("menu.logout"));
return new ModelAndView("redirect:/accueil");
} else {
ModelAndView modelViewLogin = new ModelAndView("redirect:/");
modelViewLogin.addObject("e", "p").addObject("l", login);
return modelViewLogin;
}
} else {
ModelAndView modelViewLogin = new ModelAndView("redirect:/");
modelViewLogin.addObject("e", "l");
return modelViewLogin;
}
}
Then I opened the app inactive for some minutes. After that I went to the "accueil" path. Then the menu was not shown anymore ! The menu was got from session. So how to know that the session is expired and where is the convenient place to test it ?
By default in spring security session is stored in SessionRegistry.
By using SecurityContext you can get this info in your controller code.
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
If you want to be notified when session has expired or person logged out you can always register listener on SessionDestroyedEvent- documentation.
example:
#Component
public class LogoutListener implements ApplicationListener<SessionDestroyedEvent> {
#Override
public void onApplicationEvent(SessionDestroyedEvent event) {
//do your stuff here
}
}
Its also worth to refer to spring docs for that subject.
You can make a Interceptor,
#Component
public class RequestInterceptor extends HandlerInterceptorAdapter
In this interceptor you can control the HttpServletRequest
and check if obj exists into them and then you can throw to a new SessionExpiredException and catch with #ExceptionMapper (https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc)
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
if (request.getSession().getAttribute("user")==null) {
throw new SessionExpiredException();
}
return true;
}
I check like below. I think it might be help.
public boolean isUserLoggedIn(HttpServletRequest request) throws IOException {
SecurityContext securityContext = (SecurityContext) request.getSession().getAttribute("SPRING_SECURITY_CONTEXT");
if(securityContext != null) {
Authentication authentication = securityContext.getAuthentication();
if(null != authentication && authentication.isAuthenticated() != true)
return false;
else
return true;
} else {
return false;
}
}

Resources