How to set X-frame-options header in struts 2 - struts2

I have application with struts 2
For upload file i am using iframe as target for form submission.
It gave me error -
Load denied by X-Frame-Options: http://localhost:8081/finance/uploadFile does not permit framing.
I checked X-Frame-Options in the request and it was DENY
In order to permit X-Frame-Options, I added an interceptor like this -
#Override
public String intercept(ActionInvocation actionInvocation) throws Exception {
final ActionContext ac = actionInvocation.getInvocationContext();
HttpServletResponse response = (HttpServletResponse)ac.get(StrutsStatics.HTTP_RESPONSE);
response.setHeader("X-Frame-Options", "ALLOWALL");
return actionInvocation.invoke();
}
But still i see value of X-Frame-Options ALLOWALL,DENY
And browser gives me this error -
Multiple 'X-Frame-Options' headers with conflicting values ('ALLOWALL, DENY') encountered when loading 'http://localhost:8081/finance/uploadFile'. Falling back to 'DENY'.
I don't understand i am setting request header ALLOWALL only but from where does it get DENY.
Can somebody please help how to do it correctly.

Got answer from Alireza Fattahi's comment.
I am also using spring security along with struts. And it was spring security that was adding X-Frame-Options - DENY by default.
I made following change in my spring security configuration to change default behaviour.
<sec:headers>
<sec:frame-options policy="SAMEORIGIN"/>
</sec:headers>
in <sec:http> tag

Related

Configure the landing page after SSO authentication

I want to know how to setup the relay state with the new saml library. Basically once I am authenticated via the asserting party, I want to have a relay state url (a JSP in my application), where I should land. In the saml extensions library, as far as I know, the relay state url was set in the SAMLMessageContext object.
Actual Behaviour The mechanism of setting the page where I would be redirected to after SAML login has changed. I am not sure how to set the desired JSP where I want to land in the new library.
Expected behavior After the successful call to the assertionConsumerServiceLocation in my application, I should be taken to a Url configured by me (Relaystate). I need help in configuring this URL.
I tried to set up the relay state like this :-
Saml2AuthenticationRequestResolver authenticationRequestResolver(
RelyingPartyRegistrationResolver registrations) {
OpenSaml4AuthenticationRequestResolver authenticationRequests =
new OpenSaml4AuthenticationRequestResolver(registrations);
authenticationRequests.setRelayStateResolver(relayStateResolver);
return authenticationRequests;
}
I have defined the relayStateResolver like the following :-
private Converter<HttpServletRequest, String> relayStateResolver = (request) -> "my_desired_jsp_url_string";
Are my above configurations correct, and would they help me in landing on the desired JSP page after successful login?
Currently, below is the error I am facing with the above implementation. I am working to fix that (I need to get the Opensaml4 from Shibboleth's repository of artifacts), but wanted to know if the above configuration is correct before making that fixing effort.
Jan 03, 2023 5:54:28 AM org.apache.catalina.core.StandardWrapperValve
invoke SEVERE: Servlet.service() for servlet [dispatcher] in context
with path [/company] threw exception [Filter execution threw an
exception] with root cause java.lang.NoSuchMethodError:
org.opensaml.saml.saml2.core.AuthnRequest.setIssueInstant(Ljava/time/Instant;)V
at
org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver.lambda$resolve$1(OpenSaml4AuthenticationRequestResolver.java:60)
at
org.springframework.security.saml2.provider.service.web.authentication.OpenSamlAuthenticationRequestResolver.resolve(OpenSamlAuthenticationRequestResolver.java:133)
at
org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver.resolve(OpenSaml4AuthenticationRequestResolver.java:59)
at
org.springframework.security.saml2.provider.service.web.Saml2WebSsoAuthenticationRequestFilter.doFilterInternal(Saml2WebSsoAuthenticationRequestFilter.java:184)
at
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
Because RelayState can be used for several things and is not always used to describe the post-login redirect URL (the spec says MAY), it is not defaulted to do this.
You can configure Spring Security to redirect to the RelayState parameter by configuring a SimpleUrlAuthenticationSuccessHandler like so:
#Bean
public SecurityFilterChain appEndpoints(HttpSecurity http) {
SimpleUrlAuthenticationSuccessHandler successHandler =
new SimpleUrlAuthenticationSuccessHandler();
successHandler.setTargetUrlParameter(Saml2ParameterNames.RELAY_STATE);
http
.saml2Login((saml2) -> saml2
.authenticationSuccessHandler(successHandler)
// ...
)
// ...
return http.build();
}
You will also need to configure the relay state resolver, as you have already shown in your post.

Spring Security OAuth2 configuring failureUrl makes the url inaccessible

I have a spring security based boot application for which I have configured an endpoint names /test for which I return a test.html page
#RequestMapping("/test")
public String test() {
return "test.html";
}
The endpoint works fine by itself, however if I set it as an OAuth2 failureUrl it becomes unavailable...
http.csrf().disable()
.httpBasic().disable()
.formLogin().disable()
.authorizeRequests()
.antMatchers("/test").permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login()
.failureUrl("/test");
Is this expected behavior? When I do this, spring security properly redirects to /test on authentication failure but /test is inaccessible and it ends up showing a generated page.
The behaviour of failureUrl differs based on whether or not a custom loginPage is configured.
Since you have not customized loginPage, the framework will intercept the failure URL ("/test") and generate the default error page, which is simply the default login page with an error message.
That is why you see the generated login page with accessing "/test".
Your Controller mapping for "/test" is ignored.
To tell the framework not to generate the error page, you can configure the failureHandler instead.
http
.oauth2Login((oauth2Login) -> oauth2Login
.failureHandler(new SimpleUrlAuthenticationFailureHandler("/test"))
);
Note: This may be confusing because the Javadoc for failureUrl does not describe its behaviour properly. I have created a GitHub issue in the Spring Security backlog to fix this.

CORS issue on Swagger UI

Can someone tell me why am i getting these errors.
GET http://127.0.0.1:9000/api-docs/service.json
200 OK 4ms swagger-ui.js (line 30261)
Unable to Load SwaggerUI /api-docs/ (line 83)
Cross-Origin Request Blocked: The Same Origin Policy disallows
reading the remote resource at http://127.0.0.1:9000/api-
docs/service.json. This can be fixed by moving the resource to the
same domain or enabling CORS.
uncaught exception: Can't read from server. It may not have the
appropriate access-control-origin settings.
I am trying to run Swagger UI on port say 9090 and the Swagger API documentation at 9000 and trying to display the documentation in the UI.
I have added the CORS filter on API Documentation server (port 9000) as follows.
FilterHolder cors = swaggerUIContext.addFilter(CrossOriginFilter.class,"/*",EnumSet.of(DispatcherTyp‌ e.REQUEST));
cors.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "*");
cors.setInitParameter(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, "");
cors.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "GET,POST,HEAD");
cors.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "Content-Type, api_key, Authorization");
The Request and Response headers in firefox V33.0 are
Response Headers
Content-Length 428
Content-Type application/json
Request Headers
Accept application/json;charset=utf-8,*/*
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
Connection keep-alive
Host localhost:9000
Origin http://localhost:9090
Referer http://localhost:9090/api-docs/
User-Agent Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:33.0)
Gecko/20100101 Firefox/33.0
Here is how I am setting the CORS on server
final ResourceHandler swaggerUIResourceHandler = new ResourceHandler();
swaggerUIResourceHandler.setResourceBase("target/classes/api-docs");
final ServletContextHandler swaggerUIContext = new ServletContextHandler();
swaggerUIContext.setContextPath("/api-docs");
swaggerUIContext.setHandler(swaggerUIResourceHandler);
FilterHolder cors = swaggerUIContext.addFilter(CrossOriginFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST));
cors.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "*");
cors.setInitParameter(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, "*");
cors.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "GET,POST,HEAD");
cors.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "Content-Type, api_key, Authorization");
ServletHolder def = new ServletHolder("default", DefaultServlet.class);
def.setInitParameter("resourceBase","./http/");
def.setInitParameter("dirAllowed","false");
swaggerUIContext.addServlet(def,"/");
HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[] { swaggerUIContext, new DefaultHandler() });
server.setHandler(handlers);
Did you do something funky with the json file?
I faced the same error, while trying to modify my JSON file and seeing the changes on Chrome. Ensure that the json itself is not breaking somehow, an extra bracket, comma and so on. I started from scratch with one of the example json from the swagger live demo and I was fine. I know it's a task but worked for me, atleast the UI loaded!
You can also go through the swagger ui readme, CORS support section
If you are using Spring Security
please add this code.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().configurationSource(request ->
{
CorsConfiguration cors = new CorsConfiguration();
cors.setAllowedMethods(
Arrays.asList(HttpMethod.DELETE.name(),HttpMethod.GET.name(), HttpMethod.POST.name()));
cors.applyPermitDefaultValues();
return cors;
}).httpBasic();
}
Explanation:
In the above CorsConfiguration class I'm using two methods.
cors.applyPermitDefaultValues();
cors.setAllowedMethods(List of Request Type name);
This method cors.applyPermitDefaultValues(); will allow cross origin request for all hosts.
Usually this method support cross origin support for these 3 request type methods GET,HEAD and PUT.
If your API exposing PUT , DELETE or any other request methods. Then you need to override it by this cors.setAllowedMethods();
I was able to get it working by adding the following method to my Application. Note this also opens up the API so that you can accept CrossOrigin requests. The details of the addMapping() bit are up to you, but this example opens up everything from everywhere. Here is the full class.
#SpringBootApplication
#EnableSwagger2
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*");
}
};
}
}
I also had this issue and after inspecting the headers in the pet-store example, I found that "Access-Control-Allow-Headers" needs "Content-Type, api_key, Authorization".
Make sure that you have api_key as well as I had that missing.
I have just encounter what way be a similar problem: Swagger UI: HTTP Content-type "application/json" causes "Unable to Load SwaggerUI".
Try changing the HTTP Content-type header of your GET service.json response from "application/json" to "text/html", or even removing it. I don't know why, but it seems it makes a difference for Swagger UI.
For Springdoc OpenAPI the following fix the issue:
#OpenAPIDefinition(servers = {#Server(url = "/", description = "Default Server URL")})

MVC 5 prevents access to content via Iframe

Ever since the upgrade from MVC4 to MVC5, I have noticed an extra server header added to my web pages:
X-Frame-Options: SAMEORIGIN
I understand security benefits of adding this tag, but one of the pages is meant to be included inside an iframe from other projects (on other domains), this extra header is preventing this.
I have verified it is not the hosting IIS7 server that is adding the header, and when I downgraded back to MVC4 - the header is gone.
Does anyone know how to remove this default from MVC5?
MVC5 automatically adds the HTTP header X-Frame-Options with SAMEORIGIN. This prevents your site from being loaded into an iframe.
But we can turn this off in Application_Start in the Global.asax.cs.
Example
protected void Application_Start()
{
AntiForgeryConfig.SuppressXFrameOptionsHeader = true;
}
Update
I have written a post about this MVC5 prevents your website being loaded in an IFRAME
Try something like this in Global.asax:
protected void Application_PreSendRequestHeaders(object sender, EventArgs e)
{
HttpContext.Current.Response.Headers.Remove("X-Frame-Options");
}
EDIT:
Look at answer of Colin Bacon. It is more correct than mine.
In short - don't remove this header if you don't want to run your site in IFRAME because it will open forgery vulnerability. But if you still want to remove it - use AntiForgeryConfig.SuppressXFrameOptionsHeader = true; in Application_Start, it is more cleaner way for doing this.
If you want a little more flexibility, here's an ActionAttribute that adds/removes headers based on a whitelist. If the referrer isn't in the whitelist, then the SAMEORIGIN header is left in place. I was going to paste the code, but SO complains about the length.
https://long2know.com/2016/06/asp-net-anti-forgery-xframe-options/
Personally, I don't think it's a good idea to disable the X-Frame-Options across the whole site.I've created an ASP.NET MVC filter which removes this header and I simply apply this filter to the portions of the site that are used in iFrames e.g. widgets.
public class AllowDifferentOrigin : ActionFilterAttribute, IActionFilter
{
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
filterContext.HttpContext.Response.Headers.Remove("X-Frame-Options");
base.OnResultExecuted(filterContext);
}
}
Here is a replacement Extension method for the HtmlHelper class. It will first clear all X-Frame-Options headers and then add back a single X-Frame-Options header normally added by the built-in AntiForgeryToken method.
This technique respects the SuppressXFrameOptionsHeader setting, but has the downside of removing all previously added X-Frame-Options headers, even those with values other than SAMEORIGIN.
public static MvcHtmlString AntiForgeryTokenSingleHeader(this HtmlHelper html)
{
string token = AntiForgery.GetHtml().ToString();
HttpResponseBase httpResponse = html.ViewContext.HttpContext.Response;
httpResponse.Headers.Remove("X-Frame-Options");
if (!AntiForgeryConfig.SuppressXFrameOptionsHeader)
{
httpResponse.AddHeader("X-Frame-Options", "SAMEORIGIN");
}
return new MvcHtmlString(token);
}

asp.net mvc handle http 400 error

I have an ASP.NET MVC 4 application and I want to redirect all HTTP 400 errors to my custom error page. I was searching an hours to find a solution though HTTP 400 error isn't handled like 404 error. There are many solutions that show how to escape 400(bad request error), i.e. to allow using special characters for example in url. But I wouldn't able to find some solution to catch the exception.
Please help me to catch somehow all HTTP bad requests and redirect them to my error page.
Never redirect users in case of errors, instead return a response body for the failed request. The feature of IIS (and ASP.NET) to redirect to an error page, I believe, is fundamentally wrong, incorrect, and against the HTTP specification (because then the error is being returned for the error page resource itself, not the original request. And if it's a web-browser the user has no way of retrying, because reloading the page will return the error page again, not retrying their original failed request, which is what they want).
Anyway...
A HTTP 400 response must be generated by your application code, it isn't something that will be done automatically. A bad request is typically used when informing non-human agents (i.e. web service clients, not web browsers) that their HTTP request was missing required values or had malformed values.
You can do this in MVC by having a base controller class for all of your controllers like so:
public abstract class BaseController : Controller {
protected ActionResult Http400(String message) {
Response.StatusCode = 400;
return View(message); // you need to define a view file called "Http400.aspx" (or cshtml if you're using Razor) in your application's shared views folder
}
}
so in your application logic:
public ActionResult Foobar() {
if( IsBadRequest() ) return Http400("Bad request, try again");
}
You could do something as simple as adding adding this to your web.config
<customErrors mode="RemoteOnly">
<error statusCode="400" redirect="errorpage.html"/>
</customErrors>

Resources