Intercept websocket initial handshake in rsockets - spring-boot

I want to be able to intercept the first request a client makes to my endpoint so to be able to answer with 101 (websocket estabilished) or deny it.
Is there any interceptor I can use? I tried registering a filter bean but it seems it is just skipped, I think because I'm in a webflux application...
#Bean
public FilterRegistrationBean<ContextFilter> initialFilter() {
FilterRegistrationBean<ContextFilter> registrationBean
= new FilterRegistrationBean<>();
registrationBean.setFilter(new MyFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.setOrder(1);
return registrationBean;
}
and
public class MyFilter extends OncePerRequestFilter{
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
log.info("You know, for filtering");
filterChain.doFilter(request, response);
}

To establish the RSocket connection client must send a first frame called SETUP frame. You can catch it with the Spring #ConnectMapping annotation.
#ConnectMapping
fun onConnect(rSocketRequester: RSocketRequester, clientId: String) {
if (clientId == "wrong_client") rSocketRequester.rsocket().dispose() //to reject connection
}
To reject the connection use the rSocketRequester.rsocket().dispose() as shown above.
Note that with the SETUP frame you can pass the payload and metadata from the client as usual.

Related

Spring Boot 2.2.5 - Request method 'MOVE' not supported

I am playing around with a simple Spring Boot webapp which gets called by some software which does basic file download/upload tasks.
The software sending the Requests to my app can not be changed/modified and I came across following request being sent to my webapp:
DEBUG Received [
MOVE /database/1.tmp HTTP/1.1
Destination: http://localhost:8080/database/1
Host: localhost:8080
]
which results in
WARN Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'MOVE' not supported]
As I found out MOVE is not an enum in RequestMethod so I can not simply annotate my controller with method = RequestMethod.MOVE.
How can I handle this request?
First, you have to override Spring Boot's default firewall to allow MOVE methods:
#Bean
public HttpFirewall defaultHttpFirewall() {
final StrictHttpFirewall firewall = new StrictHttpFirewall();
Set<String> allowedHttpMethods = new HashSet<>();
allowedHttpMethods.add(HttpMethod.DELETE.name());
allowedHttpMethods.add(HttpMethod.GET.name());
allowedHttpMethods.add(HttpMethod.POST.name());
allowedHttpMethods.add(HttpMethod.PUT.name());
allowedHttpMethods.add("MOVE");
firewall.setAllowedHttpMethods(allowedHttpMethods);
return firewall;
}
Now that MOVE requests are handed over to your application, your only way (as I found out there are no controller mappings for custom methods) is to manually handle the requests in a filter:
#Component
#Slf4j
public class NonRESTFulHttpMethodRequestFilter implements Filter {
#Override
public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
if ("MOVE".equals(httpServletRequest.getMethod())) {
final HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
log.trace("Ignoring 'MOVE {}' request with 200 OK", httpServletRequest.getRequestURI());
httpServletResponse.setStatus(HttpStatus.OK.value());
} else {
filterChain.doFilter(servletRequest, servletResponse);
}
}
}

Custom Authentication Filter for Mule Http Listener

I would like to implement a Security Filter in Mule 3 extending OncePerRequestFilter from Spring Security. But I am unable to make it work because the code for authentication hadn't been reach.
Here is the code for registering the filter on mule xml.
<spring:bean id="requestContextFilter" class="com.sample.authentication.BeforeBasicAuthFilter"/>
<ss:http entry-point-ref="restAuthenticationEntryPoint">
<ss:custom-filter ref="requestContextFilter" before="FIRST"/>
</ss:http>
public class BeforeBasicAuthFilter extends OncePerRequestFilter {
private HttpServletRequest request;
public HttpServletRequest getRequest() {
return request;
}
public void setRequest(HttpServletRequest request) {
this.request = request;
}
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
this.request = request;
System.out.println("XXXX ");
filterChain.doFilter(request, response);
}
}
I believe that that filter is not registered to be used by the http listener or authentication manager. Was there a way in Mule to register a filter to be used on a http Listener? My goal is that I should be able to intercept the raw http request before the authentication will take place.
Use before BASIC_AUTH_FILTER in the custom-filter.
<ss:http entry-point-ref="restAuthenticationEntryPoint">
<ss:custom-filter ref="requestContextFilter" before="BASIC_AUTH_FILTER"/>
</ss:http>

Keycloak spring boot microservices

i have a few java micro services deployed on open shift . all of them are protected by a api-gateway application which uses keycloak for authentication & Authorization.
Down stream services need to log which user perform certain actions.
in my api-gateway application properties i have already set zuul.sensitiveHeaders to empty
zuul.sensitiveHeaders:
i can see bearer token in the downstream applications .
but how do i get the principal/user from token as downstream applications don't have keycloak dependency in gradle. ( if i add the dependency , i need to reconfigure realm and other properties ) .. is this the right way to do ?
i also tried adding a filter in api-gateway to separately set the user_name in header
#Override
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
System.out.println(" Filter doFilter "+req.getUserPrincipal());
if(req.getUserPrincipal() != null ){
res.setHeader("MYUSER",req.getUserPrincipal()==null?"NULL":req.getUserPrincipal().getName());
}
chain.doFilter(request, response);
}
But when i try to get the header in downstream microservices is null.
I wouldn't recommend doing this, or assuming that your non-web facing apps are completely secure. Realistically you should be re-validating the bearer token.
What you need is a zuul filter to add a header to the request. This is mostly from memory and you could update the filter to check if it should filter or not, that the request doesn't already contain an expected header etc.
#Component
public class AddUserHeader extends ZuulFilter {
private static final Logger LOG = LoggerFactory.getLogger(AddUserHeader.class);
#Override
public String filterType() {
return "pre";
}
#Override
public int filterOrder() {
return 0;
}
#Override
public boolean shouldFilter{
return true;
}
#Override
public Object run() {
RequestContext.getCurrentContext().addZuulRequestHeader("MYUSER", SecurityContextHolder.getAuthentication().getPrincipal().getName());
return null;
}

dynamically add param to userAuthorizationUri in oauth2

Sometimes user's refresh token in local DB becomes stale. To replenish I'm trying to add prompt=consent param while making the oauth2 call. I was trying to #Autowire AuthorizationCodeAccessTokenProvider in my config class and in the afterPropertiesSet I was doing a setTokenRequestEnhancer and then realized that this bean is not even initialized via spring container when i looked the following code in OAuth2RestTemplate
private AccessTokenProvider accessTokenProvider = new AccessTokenProviderChain(Arrays.<AccessTokenProvider> asList(
new AuthorizationCodeAccessTokenProvider(), new ImplicitAccessTokenProvider(),
new ResourceOwnerPasswordAccessTokenProvider(), new ClientCredentialsAccessTokenProvider()));
Searched if any spring code is calling org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider.setAuthorizationRequestEnhancer(RequestEnhancer) to learn how to access it, but no one is calling it.
Question: How to dynamically add a param to userAuthorizationUri while making oauth2 call?
Unfortunately, I haven't found an elegant solution neither. I have noticed, however, that redirect is triggered by UserRedirectRequiredException.
I was able to dynamically add request params by registering custom filter that modifies this exception on the fly.
#Component
#Order(-102)
public class EnhanceUserRedirectFilter implements Filter {
#Override
public void init(final FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
try {
chain.doFilter(request, response);
} catch (final UserRedirectRequiredException ex) {
ex.getRequestParams().put("prompt", "consent");
throw ex;
}
}
#Override
public void destroy() {
}
}
Please note, such servlet filter has to have higher precedence than Spring Security. In my case, -102 is higher precedence than Spring Security default of -100.

SSO with Spring security

I have an application, where user is pre-authorized by SSO and lands to my page, now I need to make a call to another rest api to get some data, which is running on another server, but it will be use the same authentication. So I just wanted to know, how I can provide the authentication process? Do I need to set the cookie what I am getting from the incoming request.
When the request lands on your page it should have a token or key, in the http AUTHORIZATION header, this should be used with a filter
public class AuthFilter extends OncePerRequestFilter {
private String failureUrl;
private SimpleUrlAuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
try {
// check your SSO token here
chain.doFilter(request, response);
} catch (OnlineDriverEnquiryException ode) {
failureHandler.setDefaultFailureUrl(failureUrl);
failureHandler.onAuthenticationFailure(request, response, new BadCredentialsException("Captcha invalid!"));
}
}
public String getFailureUrl() {
return failureUrl;
}
public void setFailureUrl(String failureUrl) {
this.failureUrl = failureUrl;
}
}
Also read this post on how to set up the auto config. Spring security without form login

Resources