CORS Authorization polymer and goapp golang - google-app-engine

I have polymer frontend which interact with goapp server. Everything works fine as long as I do not pass authorization token in header. Here is the code at Polymer side
<iron-ajax
auto
url="http://localhost:8080/ephomenotes"
handle-as="json"
last-response="{{response}}"
headers="[[_computeHeader()]]"
debounce-duration="300"></iron-ajax>
_computeHeader() {
var token = localStorage.getItem("savedToken");
var obj = {};
obj.Authorization = "Bearer " + token;
return obj;
//return {"Authorization": "Bearer " + token};
}
At golang server side
w.Header().Set("Access-Control-Allow-Credentials", "true")
if origin := r.Header.Get("Origin"); origin != "" {
w.Header().Set("Access-Control-Allow-Origin", origin)
}
w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
if r.Method == "OPTIONS" {
return
}
Please note is I remove headers="[[_computeHeader()]]" from polymer code then it works..However with Authorization token it throws following error.
XMLHttpRequest cannot load http://localhost:8080/ephomenotes. Response
to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:8081' is therefore not allowed
access.
Please help

Resolved the issue ..
created new route for options
r.OPTIONS("/ephomenotes", optionsheader)
r.GET("/ephomenotes", env.EPHomePage)
This is the new function.
func optionsheader(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
w.Header().Set("Access-Control-Allow-Credentials", "true")
if origin := r.Header.Get("Origin"); origin != "" {
w.Header().Set("Access-Control-Allow-Origin", origin)
}
w.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
// w.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
}
However I am not sure, why this one worked?

Related

Jeresy CORS filter working but React rest GET failing still with header ‘access-control-allow-origin’ is not allowed

I create a rest react front end to talk to a Jersey servlet on tomcat on the back end for RH 8.6. When react tried to do on REST GET or POST commands I got the "‘access-control-allow-origin’ is not allowed according to header" error. So I then added the CORS filter which was suppose to fix the origin problem, but the react client is still failing. I have tried different filters but there is no change. I assume the problem is in the react GET fetch but it looks ok with me and gets a header back when mode: 'no-cors' is set. In the debugger the CORSFilter class gets the GET, but it does not reach the resource class endpoint so its getting rejected.
Using postman I have verified the CORSFilter is inserting the values in the response as you can see here.
POST http://localhost:8080/rtc-servlet/mcd/location
Headers from postman tool:
Status Code: 200
access-control-allow-credentials: true
access-control-allow-headers: X-Requested-With, CSRF-Token, X-Requested-By, Authorization, Content-Type
access-control-allow-methods: API, GET, POST, PUT, DELETE, OPTIONS, HEAD
access-control-allow-origin: *
access-control-max-age: 151200
connection: keep-alive
content-length: 701
content-type: application/json
date: Sat, 10 Dec 2022 02:52:19 GMT
keep-alive: timeout=20
servlet code:
#Provider
public class CORSFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
throws IOException {
// *(allow from all servers) OR https://crunchify.com/
responseContext.getHeaders().add("Access-Control-Allow-Origin", "*");
// As part of the response to a request, which HTTP headers can be used during the actual request.
responseContext.getHeaders().add("Access-Control-Allow-Headers",
"X-Requested-With, CSRF-Token, X-Requested-By, Authorization, Content-Type");
Also tried these options:
"Access-Control-Allow-Headers", "origin, content-type, accept, authorization");
responseContext.getHeaders().add("Access-Control-Allow-Credentials", "true");
responseContext.getHeaders().add("Access-Control-Allow-Methods",
"API, GET, POST, PUT, DELETE, OPTIONS, HEAD");
// How long the results of a request can be cached in a result cache.
responseContext.getHeaders().add("Access-Control-Max-Age", "151200");
}
}
#GET // read in updated/original files
#Produces(MediaType.APPLICATION_JSON) // what format we send back
public JsonObject getLocationValues() {
System.out.println("Called location getLocationValues ");
return locationRepository.readConfigFile(false);
}
React Rest GET fetch:
const urll1 = "http://localhost:8080/rtc-servlet/mcd/location";
useEffect(() => {
const fetchPost = async () => {
await fetch(urll1, {
// mode: 'no-cors',
headers: {
'Content-Type': 'application/json',
"Accept": "application/json",
"Access-Control-Allow-Origin": "*",
},
})
.then((response) => {
if (response.ok) {
response.json().then(data => {
console.log("response fetchPost :" + JSON.stringify(data));
setPosts1(data);
});
} else {
console.log("response was not ok");
}
})
.catch((err) => {
console.log(err.message);
});
};
fetchPost();
}, []);
The console error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/rtc-servlet/mcd/location. (Reason: header ‘access-control-allow-origin’ is not allowed according to header ‘Access-Control-Allow-Headers’ from CORS preflight response).
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/rtc-servlet/mcd/location. (Reason: CORS request did not succeed). Status code: (null).
NetworkError when attempting to fetch resource.
So does anyone see that I am doing wrong?
After read the CORS not working posts in stackoverflow again I came across a commit about getting the origin from the header and then setting Access-Control-Allow-Origin to it vs. "*" and react on port localhost:3000 started to get responses back from the localhost:8080 servlet (origin is being set to "localhost:3000"). This was the forum string if you want to read up on it:
How to enable Cross domain requests on JAX-RS web services?.
So the change in the filter class is as follows:
String origin = requestContext.getHeaderString("origin");
if ((origin != null) && (!origin.isEmpty())) {
headers.add("Access-Control-Allow-Origin", origin);
} else {
// *(allow from all servers) OR https://crunchify.com/
headers.add("Access-Control-Allow-Origin", "*");
}
headers.add("Access-Control-Allow-Credentials", "true");
and in the js script "Access-Control-Allow-Origin": "*" was deleted:
await fetch(urll1, {
headers: {
'Content-Type': 'application/json',
"Accept": "application/json"
},
})
I am not sure if I now need the else since "*" didn't work for me, but I left it in. If its not needed or I am just doing something that sort of works because I am using firefox please let me know.

Codeigniter 4 restful api return cors error when using authorization bearer token

On the frontend I'm using react and sending the request via axios
import axios from "axios";
import { getToken } from "./auth";
const api = axios.create({
baseURL: import.meta.env.VITE_API_URL,
});
api.interceptors.request.use((config) => {
const token = getToken();
if (token && config && config?.headers) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
export default api;
And in backend i'm using codeigniter 4. But when add a authorization bearer token in request, return cors error.
Access to XMLHttpRequest at 'http://localhost:8080/v1/user' from origin 'http://127.0.0.1:5173' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
<?php
namespace App\Filters;
use CodeIgniter\Filters\FilterInterface;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
class Cors implements FilterInterface
{
public function before(RequestInterface $request, $arguments = null)
{
$origin = base_api();
header("Access-Control-Allow-Origin: {$origin}");
header("Access-Control-Allow-Headers: X-API-KEY, Origin,X-Requested-With, Content-Type, Accept, Access-Control-Requested-Method, Authorization");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS, PATCH, PUT, DELETE");
$method = $_SERVER['REQUEST_METHOD'];
if($method == "OPTIONS") {
die();
}
}
public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)
{
//
}
}
Has anyone had a similar error?
I've looked everywhere for a solution, but I couldn't find it.

ERR_EMPTY_RESPONSE error in authorization Laravel

I have a web service with Laravel that solved the CORS Origin problem, but the next problem is that requests that have authorization headers return the following error server.
OPTIONS https://sandbox.example.com / api / v1 / user / net profile :: ERR_EMPTY_RESPONSE
I'm currently using cloudflare and wanted to know if this is a CDN or something else on the server.
This is preflight requests.
You need allow OPTIONS request. In first you need create CORS middleware
<?php
namespace App\Http\Middleware;
use Closure;
class Cors
{
public function handle($request, Closure $next)
{
$headers = [
'Access-Control-Allow-Methods'=> 'POST, GET, OPTIONS, PUT, DELETE',
'Access-Control-Allow-Headers'=> 'X-Requested-With, Content-Type, Accept, Origin, Authorization',
'Access-Control-Allow-Origin' => '*'
];
if($request->getMethod() === 'OPTIONS') {
// The client-side application can set only headers allowed in Access-Control-Allow-Headers
return \response('', 200, $headers);
}
$response = $next($request);
foreach($headers as $key => $value)
$response->header($key, $value);
return $response;
}
}
then add in Http/Kernel.php in array $middleware:
protected $middleware = [
// other middlewares
Cors::class
];
After it all requests with type OPTIONS will return response 200 with headers.

AngularJS $http, CORS and Basic authentication with Jersey

I am learning on AngularJS. I have created the sample project with CORS with Basic Authentication. My server side code is Jersey Rest. But Still I am getting 403 Forbidden Error. I don't understand. Am I missing something. My code is given below. Please help me to solve it.
ServerCode--
/*
* This is the controller level Code to get all UserlogInHistoryAngular
* information
*/
#GET
#Path("/getall")
#Produces({
MediaType.APPLICATION_XML,
MediaType.APPLICATION_JSON
})
public Response getAllUserLogInHistoryAngular() {
log.info("Controller layer for Get All UserlogInHistory");
UserLoginHistoryService userLogInHistoryService = new UserLoginHistoryService();
GenericEntity < List < UserLogInHistory >> userLoginHistory = new GenericEntity < List < UserLogInHistory >> (
userLogInHistoryService.getAllUserlogInHisotry()) {};
return Response
.status(200)
.entity(userLoginHistory)
.header("Access-Control-Allow-Credentials", true)
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods",
"GET, POST, DELETE, PUT, OPTIONS")
.header("Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Authorization, X-CSRF-Token, Accept-Version, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name")
.allow("OPTIONS").build();
}
}
AngularJS Code--
var myapp = angular
.module('myapp', ['angularUtils.directives.dirPagination']);
myapp.config(function($httpProvider) {
//Enable cross domain calls
$httpProvider.defaults.withCredentials = true;
$httpProvider.defaults.useXDomain = true;
});
myapp.controller('customerController', function($scope, $http) {
var encodingstring = window.btoa("numery" + ":" + "password");
console.log(encodingstring);
$http({
withCredentials: true,
headers: {
'Authorization': 'Basic ' + encodingstring,
'Content-Type': 'application/json; charset=utf-8'
},
method: "GET",
url: "http://localhost:8080/userloginhistoryapi/rest/secured/userloginhistory/getall"
}).then(function(response) {
$scope.lstUser = response.data;
//$log.info(response);
console.log(response.data);
console.log($scope.lstUser);
})
$scope.sortColumn = "name";
$scope.reverseSort = false;
$scope.sortData = function(column) {
$scope.reverseSort = ($scope.sortColumn == column) ? !$scope.reverseSort : false;
$scope.sortColumn = column;
};
$scope.getSortColumn = function(column) {
if ($scope.sortColumn == column) {
return $scope.reverseSort ? 'arrow-down' : 'arrow-up';
}
return '';
};
function getSelectedIndex(id) {
for (var i = 0; i < $scope.listCustomers.length; i++)
if ($scope.listCustomers[i].id == id)
return i
return -1;
};
Error--
angular.js:13018 OPTIONS http://localhost:8080/userloginhistoryapi/rest/secured/userloginhistory/getall 403 (Forbidden)
(anonymous) # angular.js:13018
sendReq # angular.js:12744
serverRequest # angular.js:12485
processQueue # angular.js:17396
(anonymous) # angular.js:17444
$digest # angular.js:18557
$apply # angular.js:18945
bootstrapApply # angular.js:1939
invoke # angular.js:5108
doBootstrap # angular.js:1937
bootstrap # angular.js:1957
angularInit # angular.js:1842
(anonymous) # angular.js:35431
trigger # angular.js:3491
(index):1 Failed to load http://localhost:8080/userloginhistoryapi/rest/secured/userloginhistory/getall: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8081' is therefore not allowed access. The response had HTTP status code 403.
angular.js:15018 Possibly unhandled rejection: {"data":null,"status":-1,"config":{"method":"GET","transformRequest":[null],"transformResponse":[null],"jsonpCallbackParam":"callback","withCredentials":true,"headers":{"Authorization":"Basic bnVtZXJ5OnBhc3N3b3Jk","Accept":"application/json, text/plain, */*"},"url":"http://localhost:8080/userloginhistoryapi/rest/secured/userloginhistory/getall"},"statusText":"","xhrStatus":"error"}
(anonymous) # angular.js:15018
(anonymous) # angular.js:11302
processChecks # angular.js:17428
$digest # angular.js:18557
$apply # angular.js:18945
done # angular.js:12799
completeRequest # angular.js:13056
requestError # angular.js:12972
error (async)
(anonymous) # angular.js:12985
sendReq # angular.js:12744
serverRequest # angular.js:12485
processQueue # angular.js:17396
(anonymous) # angular.js:17444
$digest # angular.js:18557
$apply # angular.js:18945
bootstrapApply # angular.js:1939
invoke # angular.js:5108
doBootstrap # angular.js:1937
bootstrap # angular.js:1957
angularInit # angular.js:1842
(anonymous) # angular.js:35431
trigger # angular.js:3491
VM2032:185 [CodeLive] HTTP detected: Connecting using WS
VM2032:109 [CodeLive] Connected to CodeLive at ws://127.0.0.1:42529
bundle.js:10 license url https://www.genuitec.com/go/webclipse-buy-now
So here's what's going on. The CORS Preflight request is an OPTIONS request. This request happens prior to the real request. It checks with the server to see if the request is allowed. In response to the preflight request, the server should send back the Access-Control-X-X headers like you are in your getAllUserLogInHistoryAngular method.
So what is happening in your case during the preflight, is that it hits the Basic Auth filter and automatically gets rejected without adding the CORS response headers. Your putting the CORS response headers in the resource method does nothing and is useless. Generally the CORS should be handled in a filter so it handles all requests prior to hitting the resource methods.
Here's what you should do. Just like you did for Basic Auth, use a ContainerRequestFilter to handle the CORS. You want this filter to be called before the Auth filter because the CORS preflight doesn't care about authentication and it will not send the authentication credentials with the request. In this filter, you should check to see if it is a CORS preflight request. Generally this can be done by checking for an OPTIONS method and he presence of the Origin header. If it is a preflight, then abort the request and add the CORS headers in a ContainerResponseFilter. It might look something like
#Provider
#PreMatching
public class CorsFilter implements ContainerRequestFilter, ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext request) throws IOException {
if (isPreflightRequest(request)) {
request.abortWith(Response.ok().build());
return;
}
}
private static boolean isPreflightRequest(ContainerRequestContext request) {
return request.getHeaderString("Origin") != null
&& request.getMethod().equalsIgnoreCase("OPTIONS");
}
#Override
public void filter(ContainerRequestContext request, ContainerResponseContext response)
throws IOException {
if (request.getHeaderString("Origin") == null) {
return;
}
if (isPreflightRequest(request)) {
response.getHeaders().add("Access-Control-Allow-Credentials", "true");
response.getHeaders().add("Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS, HEAD");
response.getHeaders().add("Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Authorization, X-CSRF-Token, " +
"Accept-Version, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name");
}
response.getHeaders().add("Access-Control-Allow-Origin", "*");
}
}
Notice it's a #PreMatching filter, which will cause it to be called before your Auth filter (assuming that filter is not also a pre-matching filter, in which case you should also use the #Priority annotation).
What this filter does is check to see if the request is a preflight request, and if it is, it aborts the entire request with a 200, which causes the request to skip the resource method, skip all other request filters after it, and jump to the response filter. In the response filter, we check to see if it is preflight by checking a property we set earlier. If it is, then we set the CORS response headers. If you want learn more about CORS and more about this specific filter implementation, check out this post.
So no here's the flow of what will happen
Client Browser Server
------ ------- ------
Request endpoint -------> Remembers request -------> Sends back CORS
But first sends response headers
CORS preflight from CorsFilter
|
Grabs original <----------------+
request, sends it
|
+----------------> Skips CorsFilter,
Goes to Auth filter,
Goes to resource
Sends resource response
|
Handle response <------- Receives response <----------------+
Gives it to client

CSRF & CORS issue with angularjs and spring security

Struggling for quite some time. I am having Angular.js at front with Java/J2EE (RESTFul) at the backend with Spring security (Enabled Cors-filter). Spring security works perfectly fine except when I try to enable csrf protection. Below is my code I tried for csrf:
My CSRF filter
public class CsrfHeaderFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class
.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie == null || token != null && !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
}
Security configuration has below code:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.and()
.formLogin()
.successHandler(authSuccess)
.failureHandler(authFailure)
.and()
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.antMatchers("/admin/**").access("hasRole('ADMIN')")
.antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
.and()
.addFilterBefore(corsFilter, HeaderWriterFilter.class)
.addFilterAfter(csrfHeaderFilter, CsrfFilter.class)
.csrf().csrfTokenRepository(csrfTokenRepository());
//.csrf().disable();
}
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
Had to modify CORS filter to add X-XSRF-TOKEN header name inside Access-Control-Allow-Headers as initially it was giving this error.
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-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", "X-XSRF-TOKEN, x-requested-with, Content-Type");
chain.doFilter(req, res);
}
My angular js code:
$scope.login = function () {
$http.post("http://localhost:9090/cynosureserver/login", "username=" + $scope.user.name +
"&password=" + $scope.user.password, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-XSRF-TOKEN': $cookies.get('XSRF-TOKEN')
}
}).then(function (data) {
alert("login successful" + JSON.stringify(data));
}, function (err) {
alert("error logging in" + JSON.stringify(err));
});
};
I have debug points set up. After login form it goes to Csrf filter. But never hit my "CustomUserDetailsService". The problem is I always get 403 response saying:
HTTP Status 403 - Expected CSRF token not found. Has your session expired?
If I make a simple Get request it is successful and also "XSRF-TOKEN" cookie is received inside Response Header.
But for my post method I am unable to proceed.
I am seeing below:
Status Code:403 Forbidden
Remote Address:[::1]:9090
Response Headers
Access-Control-Allow-Headers:X-XSRF-TOKEN, x-requested-with, Content-Type
Access-Control-Allow-Methods:POST, GET, PUT, OPTIONS, DELETE
Access-Control-Allow-Origin:*
....
Set-Cookie:JSESSIONID=5DE6DB8B5E31DC77DC4ED28600445615; Path=/cynosureserver/; HttpOnly
X-Content-Type-Options:nosniff
X-Frame-Options:DENY
X-XSS-Protection:1; mode=block
Request Headers
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate
...
Content-Type:application/x-www-form-urlencoded
Host:localhost:9090
Origin:http://localhost:9000
Referer:http://localhost:9000/
X-XSRF-TOKEN:7c2057b5-0f1a-4dc1-bab4-c8f000a2ae2d
Form Data
username:manisha
password:123456
I tried many different combinations but nothing seems to work, Please help me - what am I missing ? I am totally clueless here. Sorry for lengthy post.

Resources