Error in Zuul SendErrorFilter during forward - netflix-zuul

When my Zuul Filter is unable to route to a configured URL, the 'RibbonRoutingFilter' class throws a ZuulException saying "Forwarding error" and the control goes to the 'SendErrorFilter' class.
Now when the SendErrorFilter class tries to do a forward, another exception happens during this forward call.
dispatcher.forward(ctx.getRequest(), ctx.getResponse());
The exception happening during this forward call is
Caused by: java.lang.IllegalArgumentException: UT010023: Request org.springframework.cloud.netflix.zuul.filters.pre.Servlet30WrapperFilter$Servlet30RequestWrapper#6dc974ea was not original or a wrapper
at io.undertow.servlet.spec.RequestDispatcherImpl.forward(RequestDispatcherImpl.java:103) ~[undertow-servlet-1.1.3.Final.jar:1.1.3.Final]
at org.springframework.cloud.netflix.zuul.filters.post.SendErrorFilter.run(SendErrorFilter.java:74) ~[spring-cloud-netflix-core-1.0.0.RELEASE.jar:1.0.0.RELEASE]
at com.netflix.zuul.ZuulFilter.runFilter(ZuulFilter.java:112) ~[zuul-core-1.0.28.jar:na]
at com.netflix.zuul.FilterProcessor.processZuulFilter(FilterProcessor.java:197) ~[zuul-core-1.0.28.jar:na]
Finally when the control comes to my custom ZuulErrorFilter , i do not get the original exception. Instead the exception object i get is the one that occurs during the forward.
Update:
I found that a errorPath property can be configured to point to a Error Handling Service. If it is not configured, Zuul by default looks for a service named /error and tries to dispatch to that service. Since we did not have any service for /error , the dispatcher.forward() was throwing error.
Question
How can we skip this fwd to an error handling service ? We have a ErrorFilter to log the error. We do not want to have a error handling service.

We had faced the same issue and there is a simple solution to fix the Undertow "eating" the original exception, following my blog post:
http://blog.jmnarloch.io/2015/09/16/spring-cloud-zuul-error-handling/
You need to set the flag allow-non-standard-wrappers to true. In Spring Boot this is doable through registering custom UndertowDeploymentInfoCustomizer. Example:
#Bean
public UndertowEmbeddedServletContainerFactory embeddedServletContainerFactory() {
UndertowEmbeddedServletContainerFactory factory = new UndertowEmbeddedServletContainerFactory();
factory.addDeploymentInfoCustomizers(new UndertowDeploymentInfoCustomizer() {
#Override
public void customize(DeploymentInfo deploymentInfo) {
deploymentInfo.setAllowNonStandardWrappers(true);
}
});
return factory;
}
Now regarding the question, either way I would highly encourage you to implement your own ErrorController, because otherwise you may experience odd Spring Boot behaviour (in our setup - ralying on the default was always generating the Whitelabel error page with 200 HTTP status code - which never happens on Tomcat in contradiction) and in this way was not consumable by AJAX calls for instance.
Related Github issue: https://github.com/spring-cloud/spring-cloud-netflix/issues/524

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.

How can I customize exception mappings of default AuthenticationEventPublisher in Grails Spring Security Plugin

Background:
In my project, I needed to have two factor authentication (by sending OTP to registered email) which I implemented by extending DaoAuthenticationProvider.
In order to identify reason of why OTP authentication has failed, my custom authentication provider throws new custom exceptions for example BadOtpException, ExpiredOtpException, ConsumedOtpException. All these exceptions are subclasses of BadCredentialsException. This authentication flow is working fine.
Issue:
The Authentication events that were earlier getting published while I was using DaoAuthenticationProvider are now not getting published with my custom authentication provider.
Cause:
Upon some troubleshooting I figured out that Grails Spring Security Core plugin uses DefaultAuthenticationEventPublisher to publish the events. And this class publishes events on the basis of exception mappings which contain exception name vs event name to resolve the event that needs to be published whenever exception occurs. And these mappings are configured in its constructor.
Since mappings of my custom exceptions are not present in this constructor, the authentication failure events are not getting published.
Tried Solution:
I tried overriding DefaultAuthenticationEventPublisher and added new exception mappings by invoking super.setAdditionalExceptionMappings(). Here is the custom event publisher:
class CustomAuthenticationEventPublisher extends DefaultAuthenticationEventPublisher {
CustomAuthenticationEventPublisher() {
}
CustomAuthenticationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
super(applicationEventPublisher)
println('CustomAuthenticationEventPublisher')
Properties exceptionMappings = new Properties()
exceptionMappings.setProperty(BadOtpException.class.name, AuthenticationFailureBadCredentialsEvent.class.name)
super.setAdditionalExceptionMappings(exceptionMappings)
}
}
In resources.groovy, I registered my custom event publisher using following:
beans = {
authenticationEventPublisher(CustomAuthenticationEventPublisher)
}
But above solution is not working. Even the println() statement in the constructor is not getting logged. Seems like the bean is not getting registered.
Am I doing anything wrong in the above solution?
Is there any other way I can override the exception mappings?
With bit of more troubleshooting, I realized that zero argument constructor of the class CustomAuthenticationEventPublisher was being called instead of the other one.
So I tried setting the exception mappings in constructor and it worked.
Here is the code that worked form me:
class CustomAuthenticationEventPublisher extends DefaultAuthenticationEventPublisher {
CustomAuthenticationEventPublisher() {
println('CustomAuthenticationEventPublisher')
Properties exceptionMappings = new Properties()
exceptionMappings.setProperty(BadOtpException.class.name, AuthenticationFailureBadCredentialsEvent.class.name)
super.setAdditionalExceptionMappings(exceptionMappings)
}
CustomAuthenticationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
super(applicationEventPublisher)
}
}
Thanks.

#Inject into Jax-rs resource: CWWAM0002E: An exception occurred while merging an annotation into deployment descriptor:

I am getting a weird exception when I deploy Rest sevice locally to my WAS 85 environment in eclipse:
CWWAM0002E: An exception occurred while merging an annotation into deployment descriptor: com.ibm.wsspi.amm.merge.MergeException: Unable to find EnterpriseBean for class WackyDoodleResource
com.ibm.wsspi.amm.merge.MergeException: Unable to find EnterpriseBean for class WackyDoodleResource
This is not my real code but here is how I set it up with names changed to protect the innocent:
#Path("/wacky-doodle-resource")
public class WackyDoodleResource{
#Context UriInfo uriInfo
#Context SecurityContext securityContext;
#Inject WackyDoodleEJB wackyDoodleEJB;
#POST
#Consumes(MediaType.APPLICATIONI_JSON)
#RolesAllowed("WACKYDOODLES")
#Produces(MediaType.APPLICATIONI_JSON)
public Response createWackyDoodle(WackyDoodleRequestRO requestRO{
String response = null;
response = wackyDoodleEJB.createWackyDoodle(requestRO)
}
return Response.ok(response)).build();
}
#Default
#Singleton
public class WackyDoodleEJB implements IWackyDoodleEJB{
public String createWackyDoodle(WackyDoodleRequestRO req){
System.out.println("Do Something Wacky!");
}
}
public interface IWackyDoodleEJB{
public String createWackyDoodle(WackyDoodleRequestRO request);
}
(Simple recreation of my more complex code for illustration purposes)
I see that exception when I deploy my ear to my local Websphere server. The application appears to start up and deploy just fine (if you don't pay attention to what you find in the logs). However, when I attempt to hit any of my http request #myResources, I get this oddly nondescript message
E com.ibm.ws.webcontainer.internal.WebContainer handleRequest SRVE0255E: A WebGroup/Virtual Host to handle / has not been defined.
I suspect it has something to do with my ear not publishing correctly (the exception in my question). I honestly do not know however. So, what could be happening here? This seems like it should be pretty boilertplate stuff?
The error suggests that I should Turn my regular resource pojo into an EJB? If I add, for example, the stateless #nnotation to my class, the above exception in the logs goes away, but I am still not able to hit my sevice resources. I get the same nondescript exception. I am at a loss and I have been looking at this for an hour. If you could point me in any direction I would appreciate it.

Spring Boot - Spring Security - Multiple configurations

I try desperately to configure Spring Security in a Spring Boot application this way :
One way with custom token for all services called by the application
One way with HTTP Basic only for REST API services that will be used by another application
The combination of the two ways causes problems...
I tried multiples solutions without any success. I read this section : http://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/#multiple-httpsecurity
My code looks like this :
#Override
protected void configure(HttpSecurity http) throws Exception {
// Function called by application
http.authorizeRequests(). antMatchers(HttpMethod.GET, "MyFunction").hasAnyRole("USER");
http.addFilterBefore(xAuthTokenFilter, UsernamePasswordAuthenticationFilter.class);
// Function API REST
http.antMatcher("/api/**").authorizeRequests().anyRequest().authenticated().and().httpBasic();
// Requests blocked by default
http.authorizeRequests().anyRequest().denyAll();
}
Adding httpbasic() causes "Security filter chain: no match" for my first function.
Do you have any idea of the right syntax... ?
Thanks in advance.

WIF- ID1014: The signature is not valid. The data may have been tampered with

I've been using WIF to authenticate our new website, the STS is based upon the starter-sts implementation.
To enable this to work correctly on out load balanced environment I've used the following in the global.asax to override the default certificate behaviour.
void onServiceConfigurationCreated(object sender, ServiceConfigurationCreatedEventArgs e)
{
List<CookieTransform> sessionTransforms = new List<CookieTransform>(new CookieTransform[]
{
new DeflateCookieTransform(),
new RsaEncryptionCookieTransform(e.ServiceConfiguration.ServiceCertificate),
new RsaSignatureCookieTransform(e.ServiceConfiguration.ServiceCertificate)
});
SessionSecurityTokenHandler sessionHandler = new SessionSecurityTokenHandler(sessionTransforms.AsReadOnly());
e.ServiceConfiguration.SecurityTokenHandlers.AddOrReplace(sessionHandler);
}
This is all working just find and people have been successfully using the system, however every now and then we get a blast of :
ID1014: The signature is not valid. The data may have been tampered with.
in the event logs, so I switched on WIF tracing and saw the following mentioned in the log.
ID1074: A CryptographicException occurred when attempting to encrypt the cookie using the ProtectedData API (see inner exception for details). If you are using IIS 7.5, this could be due to the loadUserProfile setting on the Application Pool being set to false.
I have a feeling this is leading me down a dark alley as I thought because I'd changed the implementation to use RSA this shouldn't affect me.
Any ideas to help me?
The browser cookies are encrypted with "old" mechanism - DPAPI.
Therefore, when the server tries to decrypt the cookies, it fails - your code use RSA now, not DPAPI.
As a workaround, clear the browser cache, and the application will start running as expected.
I changed the implementation to amend the timeout in the ontokencreated method. This prevents the reissue.
protected override void OnSessionSecurityTokenCreated(Microsoft.IdentityModel.Web.SessionSecurityTokenCreatedEventArgs args)
{
args.SessionToken = FederatedAuthentication.SessionAuthenticationModule.CreateSessionSecurityToken(
args.SessionToken.ClaimsPrincipal,
args.SessionToken.Context,
DateTime.UtcNow,
DateTime.UtcNow.AddDays(365),
true
);
//base.OnSessionSecurityTokenCreated(args);
}
Did you try setting the loadUserProfile option to true? Does the problem still occur?
(Select the Application pool in IIS and then click "Advanced Settings" on the right. "Load User Profile" is in the "Process Model" section).
The intermittent occurrence of your error, combined with the DPAPI exception showing up in your traces suggests to me that you aren't actually overriding the cookie transform, and your service is still using DPAPI.
This might be a long shot, but in your code snippet I noticed your method override "onServiceConfigurationCreated" starts with a lower case o. Such a typo would indeed prevent you from properly overriding default WIF behavior.

Resources