Is it possible to access/create the HttpSession in the preProcess method of a PreProcessInterceptor?
(RestEasy 2.3.4)
You can access the HttpSession by injecting the HttpServletRequest using the #Context annotation and then getting the session from the request like so:
#Context
private HttpServletRequest servletRequest;
#Override
public ServerResponse preProcess(HttpRequest request, ResourceMethod method)
throws Failure, WebApplicationException
{
HttpSession session = servletRequest.getSession();
//Do something with the session here...
}
Related
First of all I'm saving a user in SessionStorage in React.
The problem is that I'm trying to make a filter that validates some data in the user saved in SessionStorage.
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterchain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String urlRequest = String.valueOf(httpServletRequest.getRequestURL());
HttpSession sesion = ((HttpServletRequest) request).getSession();
System.out.println(sesion.getAttribute("id")); // This is null
filterchain.doFilter(request, response);
}
The thing is that the session always returns null
I am calling a camel endpoint from the service task in a Camunda BPM workflow, and then an external HTTP request is sent to an endpoint and the response is saved as a property in the camel exchange, but the property is not propagated ?
#Override
public void configure() throws Exception {
from("direct:preferredPaymentMethod")
.log("PreferredPaymentMethodRoute")
.bean(PreferredPaymentMethodTransformation.class, "transform")
.setHeader(Exchange.HTTP_QUERY, simple("related.id=${in.headers.relatedId}"))
.marshal().json(JsonLibrary.Jackson)
.to("http4://localhost:9090/paymentMethods/v1/paymentMethod")
.id("PreferredPaymentMethod-http")
.unmarshal(jsonDataFormat)
.convertBodyTo(PaymentMethodResponseBean.class)
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
Map<String, Object> preferredPaymentMethodResponse = new HashMap<>();
preferredPaymentMethodResponse.put("responseCode", exchange.getIn().getHeaders().get(Exchange.HTTP_RESPONSE_CODE));
preferredPaymentMethodResponse.put("response", exchange.getIn().getBody(PaymentMethodResponseBean.class));
exchange.setProperty("preferredPaymentMethodResponse", preferredPaymentMethodResponse);
}
})
.bean(PreferredPaymentMethodTransformation.class, "processResponse")
.id("PreferredPaymentMethod-processResponse")
.routeId("PreferredPaymentMethodRoute");
}
I even tried setting the property in the bean method processResponse.
I found that while accessing ReST services from single-page applications that in order to properly allow access to ReST endpoints I had to register a CORS filter before my authentication filter. Is this less secure or a poor security practice?
My security configuration now looks like
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Inject
public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
private UserDetailsService userDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(userDetailsService)
.passwordEncoder(new BCryptPasswordEncoder());
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers("/health","/metrics", "/v1/users/register", "/swagger-ui/**", "/v2/api-docs").permitAll()
.antMatchers("/mappings", "/v1/**", "/backend-service/**").authenticated()
.and()
.httpBasic()
.realmName("serviceGateway")
.and()
.csrf()
.disable()
.headers()
.frameOptions().disable()
.and().addFilterBefore(new SimpleCORSFilter(), ChannelProcessingFilter.class);
}
}
And my SimpleCORSFilter looks like
public class SimpleCORSFilter implements Filter {
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
/**
* This method adds specific headers to the HTTP request to enable CORS
* requests
* #param request
* #param response
* #param chain
* #throws IOException
* #throws ServletException
*/
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) response;
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
res.setHeader("Access-Control-Max-Age", "3600");
res.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, Accept, x-requested-with, Cache-Control");
chain.doFilter(request, res);
}
#Override
public void destroy() {
}
}
I access the code with a simple $http call in Angular
$scope.login = function() {
$http({
method: 'GET',
url: 'https://myservice.mydomain.com:8095/v1/users/login',
headers: {
'Authorization': 'Basic ' + btoa("username:password")
}
})
.then(successCallback);
};
I am thinking that putting the CORS filter before security only means that the CORS headers will be added to every request, which doesn't seem like much of a security hole since I send no sensitive data in headers, excepting the Authorization header.
Am I thinking right here or is there something I am not seeing?
I think this is perfectly fine. In fact when your JavaScript code posts to a resource in another origin, the browser will issue a pre-flight request (OPTIONS verb) without the authorization header.
If your authentication code runs before the CORS handler, it has to make an exception for this request, to avoid returning 401 Unauthorized on the pre-flight.
I am trying to successfully authenticate a user with Spring Security using AngularJS on the front end.
Basically what is supposed to happen is:
1) A new user should be able to fill out the registration form with a unique username and password
2) Upon submit, Angular POSTs the user/pass combination to the URL specified by spring security.
3) Spring Security verifies the account and logs the user in.
4) The user's session begins and is shown as logged in on the front end.
The hangup is occurring in step 2. The information is not successfully posted to the spring login URL. My failure handler is tripped (in the code below) and the login process is halted.
POST http://localhost:8080/libroomreserve/login 401 (Unauthorized)
Here is my Spring Security Config:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Autowired
private AuthenticationFailure authFailure;
#Autowired
private AuthenticationSuccess authSuccess;
#Autowired
private EntryPointUnauthorizedHandler unauthorizedHandler;
#Autowired
private UserDetailServiceImpl userDetails;
#Override
protected void configure(HttpSecurity http) throws Exception{
http
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.and()
.formLogin()
.successHandler(authSuccess) //sets status to 200 OK
.failureHandler(authFailure) //sets status to 401 Unauthorized
.and()
.authorizeRequests()
.antMatchers("/**")
.permitAll();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetails);
}
Failure Handler:
#Component
public class AuthenticationFailure extends SimpleUrlAuthenticationFailureHandler{
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
}
}
Success Handler:
#Component
public class AuthenticationSuccess extends SimpleUrlAuthenticationSuccessHandler{
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
response.setStatus(HttpServletResponse.SC_OK);
}
}
AuthenticationEntryPoint:
#Component
public class EntryPointUnauthorizedHandler implements AuthenticationEntryPoint{
#Override
public void commence(HttpServletRequest hsr, HttpServletResponse hsr1, AuthenticationException ae) throws IOException, ServletException {
hsr1.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Access Denied.");
}
}
On the AngularJS side, this is my service:
.factory('sessionService', function($http, $base64){
var session = {};
session.login = function(data){
return $http.post("/libroomreserve/login", "username=" + data.userName + "&password" + data.password,
{
headers: {
'Content-Type' : 'application/x-www-form-urlencoded'
}
})
//.then() is a "PROMISE" which is executed after initial return function is performed
.then(function(){
console.log("Logged in the user!");
localStorage.setItem("session", {});
}, function(){
console.log("Error logging in the user...");
});
};
session.logout = function(){
localStorage.removeItem("session");
console.log("User has been logged out.");
};
session.isLoggedIn = function(){
return localStorage.getItem("session") !== null;
};
return session;
})
For reference, I am following the tutorial here by Chris Henkel. I can't find any discrepancies between his code and mine.
As an aside, the newly-registered user is being logged into the database so the credentials are available for authentication.
AngularJS
index.html
<head>
<meta name="_csrf" content="${_csrf.token}"/>
<!-- default header name is X-CSRF-TOKEN -->
<meta name="_csrf_header" content="${_csrf.headerName}"/>
</head>
SpringSecurity 3.2
Spring uses HttpSessionCsrfTokenRepository which by default gives header name for CSRF as X-CSRF-TOKEN, however Anuglar convention is X-XSRF-TOKEN
I wanted to extend HttpSessionCsrfTokenRepository and override the header name, but since it is marked final I ended up implementing a custom token repository.
#Component
public class CustomCsrfTokenRepository implements CsrfTokenRepository {
public static final String CSRF_PARAMETER_NAME = "_csrf";
public static final String CSRF_HEADER_NAME = "X-XSRF-TOKEN";
private final Map<String, CsrfToken> tokenRepository = new ConcurrentHashMap<>();
public CustomCsrfTokenRepository() {
log.info("Creating {}", CustomCsrfTokenRepository.class.getSimpleName());
}
#Override
public CsrfToken generateToken(HttpServletRequest request) {
return new DefaultCsrfToken(CSRF_HEADER_NAME, CSRF_PARAMETER_NAME, createNewToken());
}
#Override
public void saveToken(CsrfToken token, HttpServletRequest request, HttpServletResponse response) {
String key = getKey(request);
if (key == null)
return;
if (token == null) {
tokenRepository.remove(key);
} else {
tokenRepository.put(key, token);
}
}
#Override
public CsrfToken loadToken(HttpServletRequest request) {
String key = getKey(request);
return key == null ? null : tokenRepository.get(key);
}
private String getKey(HttpServletRequest request) {
return request.getHeader("Authorization");
}
private String createNewToken() {
return UUID.randomUUID().toString();
}
}
SecurityConfig.java
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Inject
private CustomCsrfTokenRepository customCsrfTokenRepository;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
// .addFilterAfter(new CsrfTokenGeneratorFilter(), CsrfFilter.class)
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.formLogin()
.loginProcessingUrl("/app/authentication")
.successHandler(ajaxAuthenticationSuccessHandler)
.failureHandler(ajaxAuthenticationFailureHandler)
.usernameParameter("j_username")
.passwordParameter("j_password")
.permitAll()
.and()
.csrf()
.csrfTokenRepository(customCsrfTokenRepository)
.and()
}
}
How can I cleanly override the header name instead of creating a custom csrfTokenRepository?
Is there any other configuration changes I need to do for Single Page
Applications such as AngularJS, as this does not work yet.
When using Java configuration for Spring Security, the following should be possible:
public void configure(final HttpSecurity http) throws Exception
{
final HttpSessionCsrfTokenRepository tokenRepository = new HttpSessionCsrfTokenRepository();
tokenRepository.setHeaderName("X-XSRF-TOKEN");
http.csrf().csrfTokenRepository(tokenRepository);
}
The complication is that single-page applications rely on AJAX and including CSRF tokens with AJAX requests is a bit complicated. When using AngularJS, the server should send a session cookie called XSRF-TOKEN upon first request and whenever a user logs in or logs out. AngularJS will then return the value of this cookie in the HTTP header X-XSRF-TOKEN with all requests, which the server can then check.