How to allow access cross origin requests ??? ( Angular, Rest, Spring ) - spring

i need some help
i am developing an app using angular with restful web service using spring framework
after calling this method from RESTController
#CrossOrigin(origins = "http://localhost:4200")
#RequestMapping(value="/search",method=RequestMethod.GET)
public Page<Bien> chercher(
#RequestParam(name="mc",defaultValue="") String mc,
#RequestParam(name="size",defaultValue="0") int page,
#RequestParam(name="page",defaultValue="5") int size) {
return bienRepository.chercher("%"+mc+"%",new PageRequest(page,size));
}
using
this.http.get('url:http://localhost:8080/searchmc=A').
map(resp=>resp.json()).
subscribe(data=>{this.pageBien=data;},err=>{console.log(err) } );
i got this problem
Failed to load url:http://localhost:8080/search?mc=A: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.
Any suggestion please!

Your get request from the client seems incorrect.
The correct one should be :
this.http.get('http://localhost:8080/search?mc=A').map(resp=>resp.json()).
subscribe(data=>{this.pageBien=data;},err=>{console.log(err) } );
What changed:
Drop "url" prefix in the get call
You include the request parameters in the url after the ?, so http://localhost:8080/search?mc=A (Use & for every next request parameter, on example http://localhost:8080/search?mc=A&size=5)

Related

Error during https call through proxy using CXF

In camel-cxf I have to call a SOAP webservice (exposed in https) through a proxy: configuring the http conduit as follows
public void configureClient(Client client) {
String proxySrv = Util.getProperty(Constants.Config.PROXY_SRV);
int proxyPort = new Integer(Util.getProperty(Constants.Config.PROXY_PORT));
log.info("Configurazione del server proxy:'"+proxySrv+"' port:'"+proxyPort+"'");
HTTPConduit conduit = (HTTPConduit) client.getConduit();
HTTPClientPolicy policy = new HTTPClientPolicy();
policy.setProxyServer(proxySrv); // set proxy host
policy.setProxyServerPort(proxyPort); // set proxy port
policy.setProxyServerType(ProxyServerType.SOCKS);
conduit.setClient(policy);
conduit.setAuthSupplier(new DefaultBasicAuthSupplier());
boolean proxyAuthEnabled = new Boolean(Util.getProperty(Constants.Config.PROXY_AUTH_EN));
String user = Util.getProperty(Constants.Config.PROXY_USER);
String pass = Util.getProperty(Constants.Config.PROXY_PASS);
log.info("Recuperati username:'+"+user+"' e password per il proxy:'"+proxySrv+"' port:'"+proxyPort+"'");
if (proxyAuthEnabled) {
ProxyAuthorizationPolicy ap = new ProxyAuthorizationPolicy();
ap.setUserName(user);
ap.setPassword(pass);
conduit.setProxyAuthorization(ap);
// conduit.getAuthorization().setUserName(user);
// conduit.getAuthorization().setPassword(pass);
log.info("Autenticazione abilitata per userName ='"+user+"' per il proxy:'"+proxySrv+"' port:'"+proxyPort+"'");
}
it works for http call (without the proxy server type set) but it doesn't work for https call. This proxy requires basic auth.
Reading various articles I saw that there is a bug in CXF that doesn't send the header authorization in the CONNECT call (and infact I'm getting 407 Authorization required -> even if with the same credentials with http calls it works).
Is there a way to fix it? I read about Olivier Billard solution
https://www.mail-archive.com/users#cxf.apache.org/msg06422.html
but I didn't undestand that solution (and I can't import at code any keystore).
Thanks
Hello I just faced this issue with the apache cxf client, the workaround suggested in the mailing list is to use the following static method of the java.net.Authenticator class :
Authenticator.setDefault(new Authenticator() {
#Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication("youruser", "yourpassword".toCharArray());
}
});
This way the basic will be set automatically on all your HttpUrlConnection that uses the proxy, since java 8 you also have to enable basic authentication for HTTPS tunneling, you can do this with the following property:
-Djdk.http.auth.tunneling.disabledSchemes=""
I hope this helps

WebAPI return 404 on PUT/DELETE operations

This seems to be a fairly common issue, but none of the SO articles I have looked at have solved this for me.
I am working on a ASP.NET WebForms/MVC application running on IIS on Windows 10 (so not IIS Express) which is using jQuery AJAX to invoke a WebAPI application on a separate server. To get around CORS issues, and to add additional processing to all API calls, we implemented a server-side proxy using MVC controllers, so each call would end up somewhere like this:
[HttpPost]
public ActionResult Timesheets_Submit(Timesheet data)
{
var processedData = ProcessTheRequestInSomeWay(data);
var client = new SdkClient();
var results = client.Timesheets.Post(processedData);
return Json(results);
}
And this all worked quite successfully.
However, we are getting rather fed up of having to implement new server-side proxy methods each time we add a new API endpoint, so we decided to create a transparent server-side proxy using WebAPI, and have that do the real work.
The transparent server-side proxy is implemented like this:
public class TransparentProxyDelegatingHandler : DelegatingHandler
{
private static readonly Uri BaseUri = new Uri("https://my.apiserver.com");
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Headers.Add("X-Forwarded-For", request.GetClientIpAddress());
request.RequestUri = new Uri(BaseUri, request.RequestUri.PathAndQuery.Replace("/Proxy", string.Empty));
ProcessRequestInSomeWay(request);
var response = await Client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
return response;
}
}
So a request to POST /Proxy/Timesheets will get translated into a call to POST https://my.apiserver.com/Timesheets and the response returned pretty much as-is.
The problem that I am having is that calls which use the PUT and DELETE verbs are being rejected as 404 Not Found by my UI (not by the API, I can still invoke that directly using e.g. Fiddler/Postman); the original proxy used those verbs, so it's not like they haven't been configured, it's just when I'm calling the delegating handler. The handler never gets invoked, so there's something happening in the routing engine that is causing MVC PUT/DELETE requests to work, but WebAPI PUT/DELETE requests to fail.
It turns out I was not registering the TransparentProxyDelegatingHandler correctly; I was registering it like this in my WebApiConfig:
configuration.MessageHandlers.Add(new TransparentProxyDelegatingHandler());
but as it turns out (thanks to https://blog.kloud.com.au/2013/11/24/do-it-yourself-web-api-proxy/), what I really wanted was:
configuration.Routes.MapHttpRoute(name: "proxy", routeTemplate: "proxy/{*path}",
handler: HttpClientFactory.CreatePipeline(
innerHandler: new HttpClientHandler(),
handlers: new DelegatingHandler[]
{
new TransparentProxyDelegatingHandler(),
}),
defaults: new { path = RouteParameter.Optional },
constraints: null);
I'm guessing that what was going on was that because I didn't have any actual ApiController implementations wired up to WebApi, it wasn't resolving correctly somehow in the early stages of the pipeline.

ratpack: implementing a custom PublicAddress to force https

I was on a pac4j mail thread discussing why the redirect url ratpack-pac4j uses is using http even when the original page request is served over https. I did some digging and it looks like ratpack-pac4j is using the InferringPublicAddress. This works for local development, but because my elasticbean host proxies 443 to 80, ratpack-pac4j thinks it's over http and uses http for the redirect url. I want this call to be over https when on the server.
I'm trying to register a custom PublicAddress class that always returns http in development mode, but https in production mode:
.registry(Guice.registry(b -> {
b
.module(SessionModule.class)
.module(ThymeleafModule.class, conf -> conf.templatesMode("LEGACYHTML5"))
.add(PublicAddress.class, ForcedHttpsPublicAddress.create()); //PublicAddress.class, PublicAddress.inferred("https"));
}))
...
static private class ForcedHttpsPublicAddress implements PublicAddress
{
static ForcedHttpsPublicAddress create() {
return new ForcedHttpsPublicAddress();
}
ForcedHttpsPublicAddress() {
}
}
But when I call ctx.get(PublicAddress.class), it's still returning InferringPublicAddress. Am I registering the custom PublicAddress incorrectly?
Got help on the Ratpack forum. I needed to bind it instead of add it.
.bind(PublicAddress.class, ForcedHttpsPublicAddress.class)

websockets and authentication with identityserver4

I am using .net core 1.1 and identityserver 4 to get tokens and validate users. The web api works fine reading the bearer token from the headers and getting the user principal claims.
Now I want to use a websocket (not SignalR) for sending notifications. I can open a ws:// channel (or wss) but token isn't sent with the headers, so in the .net core application I have no information of the user (User Claims and Identity).
How can I authenticate the user through the websocket? I did a search but couldn't find any helpful information.
Thanks
There are two main problems related to the authentication in WebSocket middleware:
Authorization should be called manually
First of all, authorization is not applied to web socket request (as it is not a controller which can be marked with Authorize attribute).
That's why in WebSocket middleware you need to call authorization by your self. This is easy to achieve by calling AuthenticateAsync extension method of the HttpContext object.
So, your middleware will be look something like this:
public class WebSocketMiddleware
{
private readonly RequestDelegate next;
public WebSocketMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext context)
{
if (!context.WebSockets.IsWebSocketRequest)
{
await this.next.Invoke(context);
return;
}
AuthenticateResult authenticateResult =
await context.AuthenticateAsync(OAuthValidationDefaults.AuthenticationScheme);
....
});
}
So, using authentication results you can check if the user is authenticated or not and then access authenticated user information.
Passing bearer token to web sockets request
For Web Socket connections, the default Authorization header does not work, because the WebSockets JS API doesn't allow setting custom parameters. To work around this limitation, the access token is passed quite often in the query string.
To make authentication middleware to use it, you need to update authentication validation options. This basically can be done in your startup script like this:
services
.AddAuthentication()
.AddOAuthValidation(options =>
{
options.Events = new OAuthValidationEvents
{
// Note: for Web Socket connections, the default Authorization header does not work,
// because the WebSockets JS API doesn't allow setting custom parameters.
// To work around this limitation, the access token is retrieved from the query string.
OnRetrieveToken = context =>
{
context.Token = context.Request.Query["access_token"];
return Task.FromResult(0);
}
};
});
The following code can be used as an example to add access token to web socket url during connection initializing:
const protocol = location.protocol === "https:" ? "wss:" : "ws:";
const wsUri = protocol + "//" + window.location.host + "/ws" + "?access_token=" + token;
this.socket = new WebSocket(wsUri);

Calling Micro-service using WebClient Sprint 5 reactor web

I am calling a micro-service in my rest controller. It works fine when ever there is a successful response from the Micro-service but if there is some error response I fails to pass on the error response back to user. Below is the sample code.
#GetMapping("/{id}/users/all")
public Mono<Employee> findAllProfiles(#PathVariable("id") UUID organisationId,
#RequestHeader(name = "Authorization", required = false) String oauthJwt) {
return webClient.get().uri(prepareUrl("{id}/users/all"), organisationId)
.header("Authorization", oauthJwt).accept(MediaType.APPLICATION_JSON)
.exchange().then(response -> response.bodyToMono(Employee.class));
}
Now if there is any JSON response with error code then web client does not pass on the error response to the controller due to which no information is propagated to the api end user.
You should be able to chain methods from the Mono API. Look for "onError" to see a number of options which allow you to define the behavior when there is an error.
For example, if you wanted to return an "empty" Employee, you could do the following:
.exchange()
.then(response -> response.bodyToMono(Employee.class))
.onErrorReturn(new Employee());

Resources