1
votes

I am using Angular 4 , JAX-RS for rest services. Angular is deployed in tomcat server and JAX-RS rest services were deployed in Websphere 8.5 App server. I am trying to secure the rest services using Basic Auth. Here is web.xml part used for resolving CORS issue and Basic Auth

<filter>
        <filter-name>CORS</filter-name>
        <filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
        <init-param>
            <param-name>cors.allowGenericHttpRequests</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>cors.allowOrigin</param-name>
            <param-value>*</param-value>
        </init-param>
        <init-param>
            <param-name>cors.allowSubdomains</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>cors.supportedMethods</param-name>
            <param-value>GET, POST, PUT, DELETE, OPTIONS, HEAD </param-value>
        </init-param>
        <init-param>
            <param-name>cors.supportedHeaders</param-name>
            <param-value>*</param-value>
        </init-param>
        <init-param>
            <param-name>cors.supportsCredentials</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>cors.maxAge</param-name>
            <param-value>-1</param-value>
        </init-param>
    </filter>
    <filter-mapping>
            <filter-name>CORS</filter-name>
            <url-pattern>/*</url-pattern>
    </filter-mapping> 

<security-role>
        <description>default</description>
        <role-name>default</role-name>
    </security-role>

     <security-constraint>
        <display-name>DefaultConstraints</display-name>
        <web-resource-collection>
            <web-resource-name>all resources</web-resource-name>
            <url-pattern>/*</url-pattern>
            <http-method>GET</http-method>
            <http-method>POST</http-method>
            <http-method>PUT</http-method>
            <http-method>HEAD</http-method>
            <http-method>TRACE</http-method>
            <http-method>DELETE</http-method>
            <http-method>OPTIONS</http-method>
        </web-resource-collection>
        <auth-constraint>
            <role-name>default</role-name>
        </auth-constraint>
    </security-constraint>  

     <login-config>
        <auth-method>BASIC</auth-method>
    </login-config>

When Angular app invokes Rest services from chrome browser with the above configuration in Java web it is throwing the error and below is seen in the browser console.

Failed to load resource: the server responded with a status of 401 (Unauthorized)

Failed to load http://localhost:9091/xxxxxxx/rest/v1/technologies: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access. The response had HTTP status code 401.

If the same angular app invokes the rest services from IE , the browser is throwing a pop-up for credentials and after succesful login, angular is able to fetch and display the records.

It is working for IE, not working for chrome.

If I remove the security constraint, basic auth, roles and only place CORS filter, Angular is able to fetch records from rest services in both chrome and IE. If fails only in chrome when security constraint.

Please help me in resolving. Let me know if there are any mistakes.

Thanks, Hari.

4

4 Answers

2
votes

This is because of your server (API) is deployed on localhost:9091, and your frontend app (Angular APP) is live on localhost:8080.

To make an api call, or better say http call, Angular has Http/HttpClient module in it, which is then implemented on native browser level, the problem here is, browser detects that the request from the app (:8080) is calling another resource (:9091) MIGHT BE A CORS request.

Definition from Wikipedia

Cross-origin resource sharing. Cross-origin resource sharing (CORS) is a mechanism that allows restricted resources (e.g. fonts) on a web page to be requested from another domain outside the domain from which the first resource was served.

In order to make sure the above mechanism work, browser prevents the calls, by making an extra call before each request. These request are of OPTIONS type request, if the server responds "yes.. CORS allowed." then browser will make your call proceed else it will throw an error (Exactly what you are getting).

Solution to this,

Use proxy while deploying your angular app.

ng serve --aot --port 3300 --proxy-config proxy-conf.json

here, I'm deploying my angular app on port:3300, and saying it, to use proxy-configuration stored in proxy-conf.json file.

Where, proxy-conf.json file has..

    [
        {
            "context": [
                "/api",
                "/auth"
            ],
            "target": "http://localhost:8001",
            "secure": false
        }
    ]

In the context array of above config, I said cli, to apply proxy only on requests with url /api,/auth only. This is something you need to customize as per your API endpoints.

The target key is to point out what is the location of your API. (I deployed my API on port :8001)

Hope it helps.!!

0
votes

You are getting this error from your browser. You are getting the error because your applications are not on the same domain. I suggest using a proxy. There is an option for that in the CLI. This way it will be a one time configuration.

An other option would be to install a CORS plugin in your browser. This however would require every developer to install it on every browser they use.

0
votes

In Chrome/Firefox, the WAS LTPA2 token cookie is not set for XMLHttprequest. After adding withCredentials:true, the http get requests were working in chrome/firefox also. Chrome is now adding the cookie after adding this in options.

return this.http.post(environment.frameworkUrl,framework,
  {withCredentials: true} );
}

But the same is not working for post requests. Chrome is not adding the cookie for post requests.