Is there a helper method to extract origin host from request (to build a link) - spring-webflux

I receive request via a router :
#Bean
public RouterFunction<ServerResponse> routerFunction() {
return nest(path(API_PATH), route(GET("/"), indexHandler::getIndex));
}
handle by a method :
public Mono<ServerResponse> getIndex(ServerRequest request) {
...
}
I need to extract the url use to request the service, I have different cases, sometimes request are direct to service, sometimes request go through proxy (and add X-Forwarded-Path,X-Forwarded-Path headers).
Is there a helper method, to extract this details from ServerRequest object ?

Related

How to send 'Origin' header in Feign Client

I am quite new in Spring Cloud Feign and trying to send HTTP header which is required by service provider. Here is the code snippet
#FeignClient(name = "authentication", url = "http://localhost:3000/api")
public interface AuthenticationService {
#PostMapping(value = "/login")
JsonNode login(#RequestHeader("Origin") String origin, #RequestBody LoginParams parameters);
}
When I try to send Origin header then server does not receive this header. But other headers like referer or x-access-token are received at server successfully.
I have also tried using RequestInterceptor and was not successful to send Origin as header.
#Component
public class HeaderInterceptor implements RequestInterceptor {
#Override
public void apply(RequestTemplate requestTemplate) {
requestTemplate.removeHeader("origin");
requestTemplate.header("origin", "http://amjad.localhost:3000/");
}
}
Any hint or help would be much appreciated.
cheers!
I had similar issue with OpenFeign. "Origin" header was blocked by defult, because it was using old Java http client.
After change to OkHttp Client, "Origin" was sent.

How to remove "Server" header from the restlet/jetty response?

I use Restlet integration with Jetty in my project. I would need to remove the "Server" header from the response as it discloses server information. But since I use Restlet integration with Jetty (restlet, jetty, org.restlet.ext.jetty.jar) the HttpConfiguration object is instantiated inside Restlet and not in my code. So I am not able to set "_sendServerVersion" as false and hence not able to remove the server header from the response. How to remove the server header from the response in this case ?
The best way to create a Filter and remove the header through the Filter:
public class ServerFilter extends Filter {
public ServerFilter(Context context) {
super(context);
}
#Override
protected void afterHandle(Request request, Response response) {
response.getHeaders().set("Server", null);
super.afterHandle(request, response);
}
}
Then use it like:
ServerFilter serverFilter = new ServerFilter(getContext());
serverFilter.setNext(router);
return serverFilter;
See: https://javadocs.restlet.talend.com/2.4/jee/api/index.html for documentation

MobileFirst 8: get client data ( IP address, request data ) in UserAuthenticationSecurityCheck

I'm trying to get some client data inside the UserAuthenticationSecurityCheck.validateCredentials method.
The IP Address is the most important for it.
In the other adapters, I'm using the HttpServletRequest:
#Context
protected HttpServletRequest request;
But this request object is always null in the UserAuthenticationSecurityCheck.
How can I get client data (IP Address or the headers) in this class?
You cannot inject the HttpServletRequest into a security check object(by design - not a bug). Once the user is authenticated, then you can make another Adapter Call, from where you can get the desired details. Unfortunately this is not documented anywhere (not to my knowledge at least).
I had a similar issue with AdapterAPI class as described here.
You can get request in security adapter but not from #Context.
Just override authorize method:
#Override
public void authorize(Set<String> scope, Map<String, Object> credentials, HttpServletRequest request, AuthorizationResponse response) {
//TODO use request object
super.authorize(scope, credentials, request, response);
}

HttpContext.Current.Request is not available in RegisterGlobalFilters

I am trying to add RequireHttpsAttribute attribute to MVC filters collection to push web site to HTTPS when it is deployed on prod server. The problem is with HttpContext.Current.Request.IsLocal line, the Request object is not available yet. Then how to check is site running localy or on prod server in RegisterGlobalFilters?
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
if (!HttpContext.Current.Request.IsLocal) //Exception here!!!
{
filters.Add(new RequireHttpsAttribute());
}
}
In this method you are to register the filters that will do the checking when the request comes in. This method will only get called once each time the application is started. So here you need to do something along the lines of:
filters.Add(new MyAuthorizeAttribute());
With MyAuthorizeAttribute being something along the lines of:
public class MyAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
If(!httpContext.Request.IsLocal)
{
**//Check for HTTPS and return false if need be**
}
}
Of course it does not need to be an AuthorizeAttribute.
EDIT
As I said before this method is called only once at the start of the application so there is no request for you to check in here. Here you can only apply filters that will be called every time a request is received. It is inside those filters that you can check request specific properties.
If you insist on using the RequireHttpsAttribute, than you either have to apply it to all methods regardless of whether the request is local or not or you have to extend RequireHttpsAttribute and override HandleNonHttpsRequest to handle local requests.

Alternative to cookie based session/authentication

Is there an alternative to the session feature plugin in servicestack? In some scenarios I cannot use cookies to match the authorized session in my service implementation. Is there a possibility to resolve the session using a token in http header of the request? What is the preferred solution for that in case the browser is blocking cookies?
I'm using ServiceStack without the built-in auth and session providers.
I use a attribute as request filter to collect the user information (id and token), either from a cookie, request header or string parameter.
You can provide this information after the user takes login. You append a new cookie to the response and inject the id and token info on clientside when rendering the view, so you can use for http headers and query parameters for links.
public class AuthenticationAttribute : Attribute, IHasRequestFilter
{
public void RequestFilter(IHttpRequest request, IHttpResponse response, object dto)
{
var userAuth = new UserAuth { };
if(!string.IsNullOrWhiteSpace(request.GetCookieValue("auth"))
{
userAuth = (UserAuth)request.GetCookieValue("auth");
}
else if (!string.IsNullOrEmpty(request.Headers.Get("auth-key")) &&
!string.IsNullOrEmpty(request.Headers.Get("auth-id")))
{
userAuth.Id = request.Headers.Get("id");
userAuth.Token = request.Headers.Get("token");
}
authenticationService.Authenticate(userAuth.Id, userAuth.token);
}
public IHasRequestFilter Copy()
{
return new AuthenticationAttribute();
}
public int Priority { get { return -3; } } // negative are executed before global requests
}
If the user isn't authorized, i redirect him at this point.
My project supports SPA. If the user consumes the API with xmlhttprequests, the authentication stuff is done with headers. I inject that information on AngularJS when the page is loaded, and reuse it on all request (partial views, api consuming, etc). ServiceStack is powerful for this type of stuff, you can easily configure your AngularJS app and ServiceStack view engine to work side by side, validating every requests, globalizing your app, etc.
In case you don't have cookies and the requests aren't called by javascript, you can support the authentication without cookies if you always generate the links passing the id and token as query parameters, and pass them through hidden input on forms, for example.
#Guilherme Cardoso: In my current solution I am using a PreRequestFilters and the built-in session feature.
My workflow/workaround is the following:
When the user gets authorized I took the cookie and send it to the client by using an http header. Now the client can call services if the cookie is set in a http-header (Authorization) of the request.
To achieve this I redirect the faked authorization header to the cookie of the request using a PreRequestFilter. Now I am able to use the session feature. Feels like a hack but works for the moment ;-)
public class CookieRestoreFromAuthorizationHeaderPlugin : IPlugin
{
public void Register(IAppHost appHost)
{
appHost.PreRequestFilters.Add((req, res) =>
{
var cookieValue = req.GetCookieValue("ss-id");
if(!string.IsNullOrEmpty(cookieValue))
return;
var authorizationHeader = req.Headers.Get("Authorization");
if (!string.IsNullOrEmpty(authorizationHeader) && authorizationHeader.ToLower().StartsWith("basictoken "))
{
var cookie = Encoding.UTF8.GetString(Convert.FromBase64String(authorizationHeader.Split(' ').Last()));
req.Cookies.Add("ss-id",new Cookie("ss-id",cookie));
req.Items.Add("ss-id",cookie);
}
});
}
}