Autowiring HttpSession give different object than HttpServletRequest - java

I use Spring Security, and I found strange behavior of framework while login. Spring Security WebAuthenticationDetails has parameter sessionId which is getting from HTTP request, and it all should be good, but in fact REST request gives me another session id. If I will autowire HttpSession and then get session id from it, I will get Spring-like id. So it seems that I have two ids for one user. Is it correct? Or I missed something?
EDITED:
For example this class will gave some session id
public class AuthenticationEventListener implements ApplicationListener<AbstractAuthenticationEvent> {
#Autowired
HttpSession httpSession;
#Override
public void onApplicationEvent(AbstractAuthenticationEvent event) {
if (event instanceof AuthenticationSuccessEvent) {
LoggedUser loggedUser = (LoggedUser) event.getAuthentication().getPrincipal();
loggedUser.initSessionParams(event.getAuthentication());
String sessionId = httpSession.getId();
}
}
}
and this method will give another one:
#RequestMapping(value = "/chart")
public Map getTestStatusesChart(HttpServletRequest request) {
String sessionId= request.getSession(false).getId();
return null;
}

So the answer is next: with condition of security Spring change session id by default. To prevent such behavior you need to disable session-fixation-protection in Spring Security config. more info by link

Related

Fetching session attributes from static methods

I have used below codes for fetching session attributes from session util class(contains static methods). Want to know that below code could be right approach in multithreaded environment or is there any better other ways for fetching sessions from util.
public static HttpSession getSession(){
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpSession session = attr.getRequest().getSession();
return session;
}
public static String getEmailIDFromSession(){
return (String)getSession().getAttribute("USER_EMAIL");
}
No, it's OK. And it is really thread safe. But from other side you should understand that it will be available only within HTTP Request Thread and from Spring MVC environment.
From other side, if you want to get that attribute from your #Controller or #Service you always can inject session there:
#Controller
class MyController {
#Autowired
private HttpSession session;
}

Send request after success login with spring security

Right now, I'm learning about implementing REST API with a Spring Security Framework.
My question is, after success login with spring security, how can i send the request to server and make sure the server know that i am have been authorized (already login with success)?
I have a some experiment code to do testing
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(classes = { WebAppConfig.class, SecurityConfig.class })
public class TheTest {
#Autowired
private WebApplicationContext wac;
#Autowired
private FilterChainProxy filterChainProxy;
protected MockMvc mockMvc;
#Before
public void setup() {
mockMvc = MockMvcBuilders//
.webAppContextSetup(wac)//
.addFilter(filterChainProxy)//
.build()//
;
}
#Test
public void testDoingArequest() throws Exception {
// login here
HttpSession session = mockMvc.perform(//
//
post("/login-process")//
.param("username", "theusername")//
.param("password", "thepassword")//
)//
.andDo(print())//
.andExpect(status().isFound())//
.andReturn().getRequest().getSession()//
;
// login is success and now trying to call request
this.mockMvc.perform(//
get("/doingRequest")//
.session((MockHttpSession) session)// <-- where this part must added to?
)//
.andExpect(status().isOk())//
.andDo(print())//
;
}
}
-
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()//
.antMatchers("/doingRequest").authenticated()//
.anyRequest().permitAll()//
.and()//
.csrf().disable()//
.formLogin()//
.loginPage("/")//
.loginProcessingUrl("/login-process")//
.defaultSuccessUrl("/");
}
-
#Controller
public class TheController {
#RequestMapping(value = "doingRequest", method = RequestMethod.GET)
#ResponseBody
public String doingSomething() {
return "Only authorized user can read this";
}
}
-
Above code is running well but i dont know how to implementing the "session" part in HTTP. I'm expecting something like put a token or something in header or url in real life application/implementation not in the testing environment. How the client get the token? How do we call the request (with token embedd) in client code.?
Are you looking for mocking a session object.If yes then you need to import the mock session object, and in the test class you can create and use the object.
import org.springframework.mock.web.MockHttpSession;
MockHttpSession session = new MockHttpSession();
session.setAttribute("variable", object);
The configuration you have will use the server side session to maintain the security context, and the link with the client is the standard servlet JSESSIONID cookie, so this has nothing to do with Spring Security. Whether you actually want a session or not will depend on the nature of your client. If there is no state maintained between the client and server, then each request from the client must be separately authenticated/authorized. This might be done using Basic authentication for example, or something like an OAuth2 access token depending on your requirements.

Jersey + Spring Context Outside of Controller

I have a Spring bean that needs information from the request, but isn't directly called from the controller (although it could be - but I'd like to try this without it)
Basically, my API makes requests to other services over thrift. When it makes the request, there's a service call like this:
authenticationService.authenticate(null, "username", "password");
The first parameter (the null) is usually a "placeholder" instance of a request context. The request context contains information about the user making the request, the originating IP, etc. This way, I get all of the details about the original caller without letting my API infrastructure leak into the backend.
However, to do this, I have an InvocationHandler that intercepts method calls made against a proxy of my service interfaces. Inside of that proxy handler, I have a RequestContextFactory wired in that creates instances of a RequestContext. Inside of this factory, I need to get information from the request. Particularly, the SecurityContext, so I can identify the user making the call.
Right now, I have:
#Provider
#Component
public class WebRequestContextFactory implements RequestContextFactory {
#Context private ContainerRequest containerRequest;
public RequestContext createRequestContext() {
}
}
Unfortunately, containerRequest is always null.
You can use ServletRequestAttributes to get the information from the request and the ServletRequestAttributes can be obtained from RequestContextHolder:
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
.currentRequestAttributes();
If the request is processed by the Spring DispatcherServlet, there is no need of any special setup. DispatcherServlet already expose all relevant state. But if the requests are processed outside of Spring's DispatcherServlet, then you need to add javax.servlet.ServletRequestListener in your application's web.xml file:
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
This will associate the request with the current thread and the associated request attributes can then be retrieved via RequestContextHolder.
In a slightly different scenario, the following worked for me. YMMV.
Replace this:
#Context private ContainerRequest containerRequest;
With this:
#Context private javax.inject.Provider<ContainerRequest> containerRequestProvider;
Then at the place in your code where you need the ContainerRequest:
ContainerRequest containerRequest = containerRequestProvider.get();
Code sample that pointed me toward this solution: https://github.com/psamsotha/jersey-okhttp-interceptor-demo/blob/b3b2da00b284e75011ea780fb37b555ea581ac96/src/main/java/com/example/stackoverflow/client/UserFactory.java
For Authentication, it's better to use container realm, or to use normal servlet.
And for Authorization, you can use Application or rest servlet. And in this kind of process, you can find the info from context annotation. Here's sample:
(#Context final SecurityContext sc, #Context Request request) {
logMe(sc);
...
}
private void logMe(final SecurityContext sc) {
try {
LOGGER.info("User=" + sc.getUserPrincipal().getName());
LOGGER.info("User Role?=" + sc.isUserInRole("user"));
LOGGER.info("Auth way=" + sc.getAuthenticationScheme());
} catch (final Exception e) {
LOGGER.debug(e);
}
}
Or:
(#Context final SecurityContext sc, #Context ContainerRequestContext request) {
...
You can create a access token that contains your desire information such as IP Address, user name etc. During the authentication phase create a custom token and put this token into spring security context. Later you could extract this token from other places such in your proxy classes. After extracting the token you validate or whatever you want.
Creating custom object and token:
public class CustomAuthentication {
private String userId;
private String password;
private String ipAddress;
}
public class CustomAuthenticationToken extends AbstractAuthenticationToken {
private CustomAuthentication customAuthentication;
public CustomAuthenticationToken(MobiLabAuthentication authentication,
Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.customAuthentication = authentication;
setAuthenticated(true);
}
public CustomAuthenticationToken() {
super(null);
setAuthenticated(false);
}
#Override
public Object getCredentials() {
return customAuthentication.getPassword();
}
#Override
public Object getPrincipal() {
return customAuthentication.getUserId();
}
}
Store the token into Spring security context
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new RestUserAuthrity("YOUR_APP_ROLE"));
//Extract IP , user and pass etc and construct CustomAuthentication instance
CustomAuthentication authentication = new CustomAuthentication(.....)
CustomAuthenticationToken authenticationToken = new CustomAuthenticationToken(
authentication, authorities);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
Validate security information from the Proxy bean
SecurityContext context = SecurityContextHolder.getContext();
Authentication authentication = context.getAuthentication();
if (authentication instanceof CustomAuthenticationToken) {
CustomAuthenticationToken token = (CustomAuthenticationToken) authentication;
//now you can get your ip address from token
}

Hibernate envers spring web app how to log username

I am using hiberbate 3.5 and spring 3.x
I have envers working and the ... _aud and revinfo record are now being written.
I now need to add the username to the audit record I'm guessing revinfo is the best place I have seen an example for seam app but nothing for spring app in jboss
Can anyone help with this please.
My main aim is to be able to record the windows authenticated user.
The Envers documentation has an answer for this if you use Seam.
public class ExampleListener implements RevisionListener {
public void newRevision(Object revisionEntity) {
ExampleRevEntity exampleRevEntity = (ExampleRevEntity) revisionEntity;
Identity identity = (Identity) Component.getInstance("org.jboss.seam.security.identity");
exampleRevEntity.setUsername(identity.getUsername());
}
}
So, I suppose your question would be how to retrieve the currently logged in user at that point if you don't use Seam? I'm sure there are several ways to do it, we do it like this.
Write a ServletFilter
In the filter get the principal from the session (or the security context if you use a security framework like Spring Security)
Store it in the log4j MDC
Code example from filter
protected void beforeRequest(final HttpServletRequest request, final String message) {
final Principal principal = request.getUserPrincipal();
final String username = principal != null ? principal.getName() : null;
if (username != null) {
MDC.put(USER, username);
}
}
protected void afterRequest(final HttpServletRequest request, final String message) {
MDC.remove(USER);
}
Later you can get the user from anywhere in your code because the MDC has a static get(String) method.

How to implement Logout feature using Spring Web Mvc

I am new to Spring Web MVC..
Can I get some example or online link that shows me how to implement logout feature using spring web mvc ?
I don't want to use the in built feature of spring security (i.e. ACEGI)..
Thanks in advance...
The trick with the session invalidation doesn't work. It seems the Spring authentication buffers the session ID somewhere and accept the COOKIE even, if the session was invalidated.
Another solution is to clear the Spring security context manually:
public void manualLogout() {
SecurityContextHolder.getContext().setAuthentication(null);
}
Here is the code, how to log in user manually (if somebody needs):
public void doManualLogin(HttpServletRequest request, String u, String p) {
UsernamePasswordAuthenticationToken token =
new UsernamePasswordAuthenticationToken(u, p);
token.setDetails(new WebAuthenticationDetails(request));
Authentication auth = authenticationProvider.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(auth);
}
where the authenticationProvider is the bean from you spring configuration which implements
org.springframework.security.authentication.AuthenticationProvider
You only have to invalidate the session and the user is logged out. This is directly supported by the servlet api: HttpSession.invalidate(). You can write one controller that does only call invalidate.
class Logout implements Controller{
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response){
ModelAndView view = //?;
request.getSession().invalidate();
return view;
}
}
#Controller
public class LogoutController {
#RequestMapping(value="/logout",method = RequestMethod.GET)
public String logout(HttpServletRequest request){
HttpSession httpSession = request.getSession();
httpSession.invalidate();
return "redirect:/";
}
}
Please use above code to implement logout filter

Categories