MVC 6 - Prevent Cache After Logout - caching

I'm using MVC 6 and I have implemented Identity 3.0 for authentication.
I'm trying to prevent the user from clicking on the browser back button after logout. The closest working solution I came across seems to be not working in MVC 6.
Could someone help?
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class NoCacheAttribute : ActionFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
filterContext.HttpContext.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
filterContext.HttpContext.Response.Cache.SetValidUntilExpires(false);
filterContext.HttpContext.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
filterContext.HttpContext.Response.Cache.SetNoStore();
base.OnResultExecuting(filterContext);
}
}

You can use it.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class NoCacheAttribute : ActionFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
filterContext.HttpContext.Response.Headers.Add("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
filterContext.HttpContext.Response.Headers.Add("Pragma", "no-cache"); // HTTP 1.0.
filterContext.HttpContext.Response.Headers.Add("Expires", "-1"); // Proxies.
base.OnResultExecuting(filterContext);
}
}

Related

CORS and CSRF to handle checkMarx XSRF attack issue ( spring boot microservice )

I am working on a project that has pending checkmarx issues (recently migrated from veracode) and there is a problem in this security stuff:
#Configuration
#EnableWebSecurity
public class Security extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.cors().and().csrf().disable();
}
}
Checkmarx don't like it and show me this:
SecurityConfiguration.java gets a parameter from a user request from
disable. This parameter value flows through the code and is
eventually used to access application state-altering functionality.
This may enable Cross-Site Request Forgery (XSRF)
Also add that the requests made in this springboot are handled with an idtoken, and according to the quick reading that I have found, the class should be well defined. (hope so)
If someone has a clue to solve what checkmarx does not like, it would be very helpful, good day!
The checkmarx scan is not liking the part where csrf is disabled completely for all URLs. If you have any specific url for which you want to enable csrf, you can add the following code.
#Configuration
#EnableWebSecurity
public class Security extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
equestMatcher csrfRequestMatcher = new RequestMatcher() {
// Disable CSFR protection on the following urls:
private AntPathRequestMatcher[] requestMatchers = {
new AntPathRequestMatcher("/login"),
new AntPathRequestMatcher("/logout"),
new AntPathRequestMatcher("/verify/**")
};
#Override
public boolean matches(HttpServletRequest request) {
// If the request match one url the CSFR protection will be disabled
for (AntPathRequestMatcher rm : requestMatchers) {
if (rm.matches(request)) { return false; }
}
return true;
} // method matches
};
httpSecurity.csrf()
.requireCsrfProtectionMatcher(csrfRequestMatcher)
.and()
// other validations.
}
}
Try the following link for detailed answer.
Spring Security 3.2 CSRF disable for specific URLs

spring boot jwt ant-mather blocking request

I'm trying to implement JWT in my Spring Boot application. I implemented WebSecurityConfig like this :
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable()
.authorizeRequests().antMatchers("/login/*").permitAll().
anyRequest().authenticated().and().
exceptionHandling().and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
Inside controller I have just a few end-points, just for testing like this :
#RestController("/login")
public class LoginController {
#PostMapping("/signup")
private void signup(#RequestBody LoginCredential loginCredential){
System.out.println("signup");
}
#PostMapping("/signin")
private void signin(#RequestBody LoginCredential loginCredential){
System.out.println("signin");
}
#GetMapping("/test")
private String test(){
return "test, working ?";
}
}
But when I posted some data in http://localhost:8080/login/signup it says 404.
Then I wrote a filter/interceptor to check where the requests end to.
And I found this : http://localhost:8080/login/signup
By : System.out.println(request.getRequestURL().toString());
I think there is some problem in my WebSecurityConfigurerAdapter in the antMatcher.
How can I resolve this problem ?
you are getting 404 because your path is not correct, the correct path is
http://localhost:8080/signup
because as per docs '/login' is logical component name.
If you wish to make this URL work
http://localhost:8080/login/signup
then you have to add RequestMapping to RestController hence you controller should look something like this:
#RestController
#RequestMapping("/login")
public class LoginController {
...
}

CORS error when accessing static resource

Despite having the following config, accessing http://localhost:8080/rooms/rooms.json gives me a CORS error - No 'Access-Control-Allow-Origin' header is present on the requested resource.
I have no problem to request any other path which is mapped by controller. What is the problem with static resources? How to allow cors request or exclude the resource paths without spring security?
Spring Boot 2.0.5
Spring Boot Web Starter 2.0.5
#Configuration
#EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/rooms/**")
.addResourceLocations("classpath:/rooms/")
.setCachePeriod(3600)
.resourceChain(true)
.addResolver(new PathResourceResolver());
}
#Override
public void addCorsMappings(final CorsRegistry registry) {
registry.addMapping("/**");
}
}
I got it working with the following configuration bean:
#Configuration
public class StaticResourcesCorsConfig
{
#Bean
public WebMvcConfigurer corsConfigurer()
{
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*");
}
};
}
}
Note, that Spring Boot will only send the Access-Control-Allow-Origin header back on a GET request, if the Origin-header is present on the request.
Update addCorsMappings like below it could work
#Configuration
#EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/rooms/**")
.addResourceLocations("classpath:/rooms/")
.setCachePeriod(3600)
.resourceChain(true)
.addResolver(new PathResourceResolver());
}
#Override
public void addCorsMappings(final CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:8080")
.allowedMethods("POST", "GET")
//.allowedHeaders("header1", "header2", "header3")
//.exposedHeaders("header1", "header2")
.allowCredentials(true).maxAge(3600);
}
}
Add #CrossOrigin(value = "*") to your controller class. You can replace * with any particular URL in case to allow that origin only.
#CrossOrigin(origins = "http://localhost")
#GetMapping("/rooms/")
public Object rooms() {
// your implementation
}
You can do in this way.
https://www.viator.com/orion/nova/public/mmblite/styles-53929dcb.css
Experienced the same problem actually, but found the root cause and a solution.
Your request was most probably cached by intermediary: load balancer, CDN or caching HTTP server in front of your application as regular non-CORS request. Then you have sent request with Origin:, but the intermediary returned you the same cached response because from point of view of the cache responses by default are identified by /path + METHOD + Host:-header which were the same. To tell caches that the request with Origin: and the regular request (without Origin: need to be cached as independent entries in any cache we need Vary: Origin header in both responses. This was fixed/implemented in Spring 5.2.x (in my case it was Spring 5.1.9), in your case it was 5.0.9 (as dependency of Spring Boot 2.0.5.). Once I upgraded to Spring 5.2.0 all was fixed once caches on the intermediary had expired. I recommend to upgrade beyond 5.2.6 (cause there were further changes in CORS handling, which are nice to have).
here is the line (which made the difference) they (Pivotal) commited into Spring: https://github.com/spring-projects/spring-framework/commit/d27b5d0ab6e8b91a77e272ad57ae83c7d81d810b#r36264428
and their bug description: https://github.com/spring-projects/spring-framework/issues/22273

Can not retrieve Principal from Spring Okta (CRA SPA)

I am currently trying to test out Okta with SPA front end (Create-React-App) and a Spring Boot application.
Currently I have the apps working, in that a user logins on the front end (via okta). The user can then access protected resources from server (spring boot). Hence the integration works well and nice.
My issue is I can't access the Principal on my Rest Controller.
ENV
Note: Spring-Security-Starter is NOT on the classpath just the OAuth2 autoconf
Spring Boot 2.0.6.RELEASE
okta-spring-boot-starter:0.6.1
spring-security-oauth2-autoconfigure:2.0.6.RELEASE'
Spring Configuration
okta.oauth2.issuer=https://dev-886281.oktapreview.com/oauth2/default
okta.oauth2.clientId={ clientId }
okta.oauth2.audience=api://default
okta.oauth2.scopeClaim=scp
okta.oauth2.rolesClaim=groups
security.oauth2.resource.user-info-uri=https://dev-886281.oktapreview.com/oauth2/default/v1/userinfo
Okta Service Configuration
Application type: Single Page App (SPA)
Allowed grant types: Implicit
Allow Access Token with implicit grant type: true
Controller
#RestController
#RequestMapping("/products")
public class ProductController {
...
#GetMapping
public ResponseEntity<List<ProductEntity>> getAllProducts(Principal principal) {
SpringBoot
#EnableResourceServer
#SpringBootApplication
public class CartyApplication {
public static void main(String[] args) {
SpringApplication.run(CartyApplication.class, args);
}
#EnableGlobalMethodSecurity(prePostEnabled = true)
protected static class GlobalSecurityConfiguration extends GlobalMethodSecurityConfiguration {
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
#Bean
protected ResourceServerConfigurerAdapter resourceServerConfigurerAdapter() {
return new ResourceServerConfigurerAdapter() {
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS,"/**").permitAll()
.anyRequest().authenticated();
}
};
}
Once again the overall integration is working fine, users can only access protected resources once they've signed in via okta, I'm just wondering how to get the users details from okta on the controller.
Thanks in advance.
P.S soz for the code dump
EDIT: Removed snippets and added full CartyApplication class
EDIT2: Added repo - https://github.com/Verric/carty-temp
I have a feeling you might be missing this:
#EnableGlobalMethodSecurity(prePostEnabled = true)
protected static class GlobalSecurityConfiguration extends GlobalMethodSecurityConfiguration {
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
I'm guessing should remove the .antMatchers("/**").permitAll() line.
See: https://docs.spring.io/spring-security/site/docs/current/reference/html/jc.html#CO3-2
I'm guessing you want to protect all/most of your endpoints? I'd recommend only allowing specific routes, and protecting everything else.

how to redirect the user to login page spring mvc?

I am new to spring mvc. I have a web application I would like to redirect user to login page when he clicks to a button in a html page, then when he logs in, I would like to send him back to the link he had originally clicked.I added a class called MyAccessDeniedHandler to the configuration package but i didn't know what to do then .
yes Kenny Tai Huynh i tried this one :
#Component("myAccessDeniedHandler")
public class MyAccessDeniedHandler implements AccessDeniedHandler {
//#Qualifier("myRequestCache")
//private RequestCache myRequestCache;
public MyAccessDeniedHandler() {
}
#Override
public void handle(HttpServletRequest arg0, HttpServletResponse arg1,
org.springframework.security.access.AccessDeniedException arg2) throws IOException, ServletException {
// TODO Auto-generated method stub
if (!arg1.isCommitted()) {
arg0.getRequestDispatcher("/signin").forward(arg0, arg1);
}
}
}

Resources