Restlet CorsFilter with ChallengeAuthenticator - angularjs

I'm building a RESTful API with the Restlet framework and need it to work with cross domain calls (CORS) as well as basic authentication.
At the moment I'm using the CorsFilter which does the job of making my webservice support CORS requests. But, when I try to use this with a simple ChallengeAuthenticator with HTTP Basic Authentication it won't work as I want it to (from a web site).
When I access the webservice directly via Chrome it works as intended, but when I try it in a small web application written in angularjs (jquery/javascript) and try to access the webservice it does not.
Basically what happens is that when a OPTIONS request is sent to my webservice it will not respond with the headers: 'Access-Control-Allow-Origin', 'Access-Control-Allow-Credentials', etc. as it should. Instead it is sending a respond with HTTP status code 401 saying that the authentication failed.. Is this because the authenticator is overriding the CorsFilter somehow?
My createInboundRoot method can be seen below.
#Override
public Restlet createInboundRoot() {
ChallengeAuthenticator authenticator = createAuthenticator();
RoleAuthorizer authorizer = createRoleAuthorizer();
Router router = new Router(getContext());
router.attach("/items", ItemsServerResource.class);
router.attach("/items/", ItemsServerResource.class);
Router baseRouter = new Router(getContext());
authorizer.setNext(ItemServerResource.class);
authenticator.setNext(baseRouter);
baseRouter.attach("/items/{itemID}", authorizer);
baseRouter.attach("", router);
// router.attach("/items/{itemID}", ItemServerResource.class);
CorsFilter corsFilter = new CorsFilter(getContext());
corsFilter.setNext(authenticator);
corsFilter.setAllowedOrigins(new HashSet(Arrays.asList("*")));
corsFilter.setAllowedCredentials(true);
return corsFilter;
}
(The authorizer and authenticator code is taken from the "official" restlet guide for authorization and authentication)
I've tried alot of changes to my code but none which given me any luck. But I noticed that when setting the argument "optional" in ChallengeAuthenticator to true (which "Indicates if the authentication success is optional") the CorsFilter does its job, but obviously the ChallengeAuthenticator does not care about authenticating the client and lets anything use the protected resources..
Has anyone had a similar problem? Or have you solved this (CORS + Authentication in Restlet) in any other way?
Thanks in advance!

I think that it's a bug of the Restlet CORS filter. As a matter of fact, the filter uses the method afterHandle to set the CORS headers. See the source code: https://github.com/restlet/restlet-framework-java/blob/4e8f0414b4f5ea733fcc30dd19944fd1e104bf74/modules/org.restlet/src/org/restlet/engine/application/CorsFilter.java#L119.
This means that the CORS processing is done after executing the whole processing chain (authentication, ...). So if your authentication failed, you will have a status code 401. It's actually the case since CORS preflighted requests don't send authentication hints.
For more details about using CORS with Restlet, you could have a look at this link: https://templth.wordpress.com/2014/11/12/understanding-and-using-cors/. This can provide you a workaround until this bug was fixed in Restlet itself.
I opened an issue in Github for your problem: https://github.com/restlet/restlet-framework-java/issues/1019.
Hope it helps,
Thierry

The CorsService (in 2.3.1 coming tomorrow) contains also a skippingResourceForCorsOptions property, that answers directly the Options request without transmitting the request to the underlying filters and server resources.

Related

Solving CORS issues when calling fetch from React App [duplicate]

This question already has an answer here:
CORS Unauthorized 401 error when calling spring rest api
(1 answer)
Closed 3 years ago.
I'm trying to send http requests from my React client app to a RestfulApi (built with Spring), but I'm facing CORS issues.
As I understand it to solve cors issue there are several ways, 2 of them that I know:
1) Install a CORS extension on your browser (your browser will be exposed to security risks, but if it's only during development and it can be enabled/disabled then I can live with it)
2) Allow headers from your server rest API- I found a spring annotation called #CrossOrigin(origins = "", allowedHeaders = "")
https://howtodoinjava.com/spring5/webmvc/spring-mvc-cors-configuration/
Using the first approach:
First call that I perform is GET login request and it works, but I'm getting back an empty response with empty headers!
Second call is another GET request to get some projects details, but I'm getting 401!
From some investigation I understood that there is a need to send the browser sessionId (stored in cookies) and pass it to the HTTP request as param in order to be authorized... but didn't manage yet making it works.
I reached this page:
https://www.baeldung.com/spring-security-cors-preflight
Adding another class to my rest server app didn't help as well:
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
// ...
http.cors();
}
}
Install a CORS extension on your browser (your browser will be exposed to security risks, but if it's only during development and it can be enabled/disabled then I can live with it)
CORS extensions tend to just inject Access-Control-Allow-* headers into responses.
They don't do everything else that needs to be done to enable CORS.
In particular, they tend not to handle the preflight requests that need before credentials can be sent in a request. So:
the browser sends a preflight request asking for permission to make a request with credentials
the server responds with an Unauthorized error because the credentials weren't sent
the extension injects Access-Control-Allow-* headers
the browser denied access to the response to the JS because the response had an Unauthorised status (the Access-Control-Allow-* headers not being sufficient to override that)
Implement a real solution when you need CORS. Browser extensions are a waste of time because the will need replacing with real solutions in the end and only work in a subset of cases in the first place.

AngularJS SpringBoot no authentication csrf protection

My system uses AngularJS 1.6 and Spring Boot2.0. My front end is just a simple form that customers can use to buy tickets for an event. When the page loads it will GET the details of the current active event, then the users can fill the form to be POSTed. No login/registration so it's just like a google form. I've built them as separate projects so they will be running in different ports. Now I want to enable csrf protection but I can't seem to make it work.
I tried to follow this tutorial but without the authentication part: https://spring.io/blog/2015/01/12/the-login-page-angular-js-and-spring-security-part-ii. When I did this I encountered a "CORS header ‘Access-Control-Allow-Origin’ missing" on the GET event details part so I added a CORS filter:
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type");
chain.doFilter(request, response);
After adding that, my GET works but I encounter the same CORS error when I POST the customer's details. I can already see the XSRF-TOKEN in the cookie when I use postman but somehow my backend blocks the incoming POST. From my understanding, angular automatically uses a received XSRF token so I didn't modify anything in the frontend when implementing spring security.
I've also tried this one: https://sdqali.in/blog/2016/07/20/csrf-protection-with-spring-security-and-angular-js/. And the exact same result, if I just follow the tutorial, CORS error on GET then when I add simple CORS filter, CORS error on POST. My filters seems to get mixed up on run time.
I've tried playing around the codes in these tutorials along with some answers to related questions here in stack but all of them don't have to deal with the CORS problem.
To begin, you should check my comment on how to enable CORS with spring-boot and spring-security.
As for CSRF protection, spring-boot 2 with spring-security enable that directly. Yet, to use it with AngularJS, you need to follow this guide:
https://docs.spring.io/spring-security/site/docs/current/reference/html5/#csrf-cookie
We are also working on a project with a frontend AngularJS 1.6 and a backend spring-boot 2, but, as we didn't deploy our frontend and our backend on the same url, we got into a problem.
Example:
https://project.company.com/frontend
https://project.company.com/backend
The cookie generated by the server was set on the domain https://project.company.com with context /backend, which was unreadable from our frontend application in AngularJS.
To fix that, we forced our server to send a cookie with a context / so that it could be read from both applications.
#Configuration
#EnableWebSecurity
public class LdapAuthenticationSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
final CookieCsrfTokenRepository csrfTokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse();
csrfTokenRepository.setCookiePath("/"); // Make sure that the cookie can be read from the backend and the frontend on the same domain.
http.csrf().csrfTokenRepository(csrfTokenRepository);
http.cors();
}
}
In the case where your applications are deployed on different domains, but with the same base like this:
https://frontend.company.com
https://backend.company.com
I would suggest to force the cookie send by the server with a domain like .company.com. But to do so, you will need to modify the way spring-security manage the cookie creation.

Spring Boot application gives "405 method not supported" exception for only Angular/HTML/JSP resources

I have an application written with Spring Boot and AngularJS. When I try to hit a REST service as part of this application, I am able to hit it with POST method wherever POST is configured for request mapping.
But if I try to request AngularJS bind pages, I get a "405 method not supported" exception. So I try to create HTML and JSP pages too, which are not bound to Angular but still, I am getting the same exception.
Where can I start debugging this, and what is the likely reason?
i am sharing here furthere details about issue.
Basically this existing application created/developed with Jhipster, angularjs, Spring boot and spring security does not allow to access html/angularjs related resources with POST from outside. I will explain here what different scenarios work and what is not not working. 1.Postman trying to access base url trying to fetch index.html from same application- Give 405 Post method not allowed.2.Created an independent Test.html in same application and trying to access it from postman- Gives 405 Post method not allowed.3.Created a service which allows POST access in same application- Able to hit service from WSO2 IS IDP and also from Postman.4.Created a separate application on tomcat and provided as callback in WSO2 IDP with starting point for SSO from base url of existing application- Able to hit callback URL on tomcat server. Firefox shows that a POST request was generated for callback URL from WSO2 IS IDP to tomcat based application 5.Created a separate application with Angular js and Spring boot and provided as callback in WSO2 IDP with starting point for SSO from base url of existing application- Able to hit callback URL on tomcat server. Firefox shows that a POST request was generated for callback URL from WSO2 IS IDP to new application with Spring boot and Angularjs. This took me down to conclusion that one of three is causing this issue
1. Spring security generated from JHipster
2. Angularjs
3. Some CORS or other filter from Spring Security is causing this issue.
Till now we have tried to different debugging methods like
1. disable CORS,
2. in angularjs-resource.js enable POST for get operation,
3. In SecurityCOnfigurer, try to permit POST method for base URL or resolve it to GET in httpsercurity authorizerequest etc.
4. Also ignoring resources in websecurity.
Application stack for existing application which we are trying to implement SSO is as below
1. Angularjs 1.5.8
2. Springboot 1.5.9.release
3. WSO2IS 5.4.1
4. WSO2AM 2.1.0
5. JHipster
Let me know if any particular area which we might have missed to analyze or different methods to try.
Thanks,
Sandeep
Try to disable CSRF in security config
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
...
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
...
}
...
}
#SpringBootApplication
#Import({
...
SecurityConfig.class
...
})
public class SpringBootApp {
...
}

Access-Control-Allow-Origin ATG Rest API

I am building a Portal using angularjs and ATG Rest API, It is giving an Error When I am trying to get Session confirmation Number using API:rest/model/atg/rest/SessionConfirmationActor/getSessionConfirmationNumber
Error:XMLHttpRequest cannot load http://IPNUMBER:Port/rest/model/atg/rest/SessionConfirmationActor/getSessionConfirmationNumber. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.
API is working fine in POSTMAN, and from the direct browser query.
Please help me on this.
You best bet is to write a simple Pipeline servlet and add it to the RestPipeline configuration. The servlet would just inject the cors headers to all Rest requests.
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import atg.servlet.*;
import atg.servlet.pipeline.*;
public class CORSHeaderServlet extends InsertableServletImpl{
public CORSHeaderServlet () {}
public void service (DynamoHttpServletRequest request,
DynamoHttpServletResponse response)
throws IOException, ServletException
{
//add headers to response.
response.addHeader("Access-Control-Allow-Origin" ,"*");
passRequest (request, response);
}
}
I didn't use this API, but problem is quite common. Have a look for example here (or any other source about CORS):
How does Access-Control-Allow-Origin header work?
If your web application and service have different domains (origins), this will not work until the service allows your application to request data. When you use Postman it works, because Postman does not send the header or uses origin, which is allowed. I don't really know how it works, but it does and it's normal.
If you are using locally hosted application just for testing purposes and both service and app will have the same origin, you have two easy solutions:
You can run web browser (e.g. Chrome) with web security disabled:
Disable same origin policy in Chrome. This disables CORS and eliminates the problem.
You can install Chrome extension called Allow-Control-Allow-Origin: *. When it's enabled, it sends origin which will be allowed by the service.
However, if your service will have different origin, then you will have to configure it to allow your application to request it.
Edit
Note one thing. If you send a request different than GET or with some custom headers, browsers will firstly send an OPTIONS request. It's called preflight request. You're service will have to handle it in order to work properly.

Symfony2 Oauth2 Server with authorization code grant, Symfony2 APIRest and Angular JS client

What I have:
-API Rest in Symfony2 using friendsofsymfony/rest-bundle exposing some resources.
-Oauth2 server in Symfony2 using FOSOAuthServerBundle.
-Client in Angular.js doing requests to the API Rest. This client currently gets to login via the authorization code grant (using Hello.js with a custom module), and gets the access token effectively.
I want these API resources secured, so:
-On API Rest app: I implemented the AuthenticationEntryPointInterface which I set as the entry_point in security.yml, to return 401 code and application/json content-type on rejected.
-Client intercepts 401 responses and sends the user to the login form.
-Client sends api rest requests with X-Access-Token set on header.
My current issues:
1) I'm not sure whether I should be setting X-Access-Token on client for requests, I understand this is the right way? Or should I leave it all to hello.js api methods?
2) I have no idea how to make the API Rest app "ask" the oauth server "is this token ok? who does it belong to?" Is this already solved in Symfony?
Thanks a lot for any answer or guideline. Feel free to require any further information or code for what I describe.
For anyone else facing a similar issue:
1) As for the client authenticated requests after login, I let hello.js hello(provider).api methods solve it. It sends access_token as a param. I didn't have to set X-Access-Token on the header or any other "hand made" touch.
2) I didn't find an out of the box solution by symfony for this. But this is what I did:
-Configured a before filter for the protected controller (see doc)
-In that method, I made a call to the API held on the OAuthServer (using this bundle)

Resources