I make an AJAX call from JavaScript client (running on machine A) to Web server (running on machine B).
Client tries to access a URL exposed by RESTful Web service (Jersey), and it is blocked with error:
Origin http://localhost/ is not
allowed by
Access-Control-Allow-Origin
In server I added 2 header parameters that allow access to any client. However it didn't help:
#Context
private HttpServletResponse servlerResponse;
#POST
#Path("testme")
public void test(){
servlerResponse.addHeader("Access-Control-Allow-Origin", "*");
servlerResponse.addHeader("Access-Control-Allow-Credentials", "true");
}
The same headers work in case of JSP:
<%
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Credentials", "true");
%>
<html>
<head><title>test jsp</title></head>
<body>
test
</body>
</html>
Am I missing something?
thanks
P.S the client part is:
$.ajax({
type: "POST",
url: "http://localhost:8080/login/testme",
dataType: 'json',
success: onLoginSuccess,
error: onLoginError
});
As a solution, we implemented javax.servlet.Filter that adds required headers to every response:
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, java.io.IOException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
// This should be added in response to both the preflight and the actual request
response.addHeader("Access-Control-Allow-Origin", "*");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.addHeader("Access-Control-Allow-Credentials", "true");
}
chain.doFilter(req, resp);
}
#epeleg This is my preferred way of doing things like this is to do filtering of response (Jersey 2.x):
#Provider
public class CORSFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext requestContext,
ContainerResponseContext responseContext) throws IOException {
responseContext.getHeaders().add("Access-Control-Allow-Origin", "*");
}
}
Related
Currently I try to make login using angular 2 to spring oauth2.
I get this error when click login in my angular:
XMLHttpRequest cannot load http://localhost:8080/REM/oauth/token. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://localhost:3000' is therefore not allowed
access.
Angular
login(username: string, password: string) {
let headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded; charset=utf-8');
headers.append('Accept', 'application/json');
let options = new RequestOptions({ headers: headers });
let params = new URLSearchParams();
params.append('grant_type', "password");
params.append('client_id', "client");
params.append('client_secret', "secret");
params.append('username', "user");
params.append('password', "pass");
return this.http.post(this.urlLogin, params.toString(), options).map(this.extractData);}
CORS
<mvc:cors>
<mvc:mapping path="/**" allowed-origins="http://localhost:3000, *"
allowed-methods="POST, GET, PUT, DELETE"
allowed-headers="X-Requested-With, Content-Type, X-Codingpedia,Authorization, Accept, Origin"
allow-credentials="false" max-age="3600" />
</mvc:cors>
Kindly find full server configuration at: https://github.com/robbyrahmana/Config
I user it in spring boot
you can see that and make some differences
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class SimpleCORSFilter implements Filter {
#Override
public void init(FilterConfig fc) throws ServletException {
}
#Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) resp;
HttpServletRequest request = (HttpServletRequest) req;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "PATCH,POST,GET,OPTIONS,DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, resp);
}
}
#Override
public void destroy() {
}
}
Hi Everyone I'm having trouble setting up a security solution for my app!!
So I have a REST API Backend which runs at http://localhost:51030 and developed with Spring Framework, and for the front side I have an Angular 2 application (the latest version A.K.A. Angular 4) which runs at http://localhost:4200.
I have set the CORS configuration in the backend as seen below:
public class CORSFilter implements Filter
{
// The list of domains allowed to access the server
private final List<String> allowedOrigins = Arrays.asList("http://localhost:4200", "http://127.0.0.1:4200");
public void destroy()
{
}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException
{
// Lets make sure that we are working with HTTP (that is, against HttpServletRequest and HttpServletResponse objects)
if (req instanceof HttpServletRequest && res instanceof HttpServletResponse)
{
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
// Access-Control-Allow-Origin
String origin = request.getHeader("Origin");
response.setHeader("Access-Control-Allow-Origin", allowedOrigins.contains(origin) ? origin : "");
response.setHeader("Vary", "Origin");
// Access-Control-Max-Age
response.setHeader("Access-Control-Max-Age", "3600");
// Access-Control-Allow-Credentials
response.setHeader("Access-Control-Allow-Credentials", "true");
// Access-Control-Allow-Methods
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
// Access-Control-Allow-Headers
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, " + CSRF.REQUEST_HEADER_NAME); // + CSRF.REQUEST_HEADER_NAME
}
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig)
{
}
}
Using this configuration only works fine, I can execute requests from the angular app to the spring back and get response and do anything.
But when I try to set up CSRF security solution nothing works.
This is the CSRF and Security configuration setted up in the backend:
public class CSRF
{
/**
* The name of the cookie with the CSRF token sent by the server as a response.
*/
public static final String RESPONSE_COOKIE_NAME = "XSRF-TOKEN"; //CSRF-TOKEN
/**
* The name of the header carrying the CSRF token, expected in CSRF-protected requests to the server.
*/
public static final String REQUEST_HEADER_NAME = "X-XSRF-TOKEN"; //X-CSRF-TOKEN
// In Angular the CookieXSRFStrategy looks for a cookie called XSRF-TOKEN
// and sets a header named X-XSRF-TOKEN with the value of that cookie.
// The server must do its part by setting the initial XSRF-TOKEN cookie
// and confirming that each subsequent state-modifying request includes
// a matching XSRF-TOKEN cookie and X-XSRF-TOKEN header.
}
public class CSRFTokenResponseCookieBindingFilter extends OncePerRequestFilter
{
protected static final String REQUEST_ATTRIBUTE_NAME = "_csrf";
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException
{
CsrfToken token = (CsrfToken) request.getAttribute(REQUEST_ATTRIBUTE_NAME);
Cookie cookie = new Cookie(CSRF.RESPONSE_COOKIE_NAME, token.getToken());
cookie.setPath("/");
response.addCookie(cookie);
filterChain.doFilter(request, response);
}
}
#Configuration
public class Conf extends WebMvcConfigurerAdapter
{
#Bean
public CORSFilter corsFilter()
{
return new CORSFilter();
}
#Override
public void addViewControllers(ViewControllerRegistry registry)
{
registry.addViewController("/login");
registry.addViewController("/logout");
}
}
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
{
#Autowired
private RESTAuthenticationEntryPoint authenticationEntryPoint;
#Autowired
private RESTAuthenticationFailureHandler authenticationFailureHandler;
#Autowired
private RESTAuthenticationSuccessHandler authenticationSuccessHandler;
#Autowired
private RESTLogoutSuccessHandler logoutSuccessHandler;
#Resource
private CORSFilter corsFilter;
#Autowired
private DataSource dataSource;
#Autowired
public void globalConfig(AuthenticationManagerBuilder auth) throws Exception
{
auth.jdbcAuthentication()
.dataSource(dataSource)
.usersByUsernameQuery("select login as principal, password as credentials, true from user where login = ?")
.authoritiesByUsernameQuery("select login as principal, profile as role from user where login = ?")
.rolePrefix("ROLE_");
}
#Override
protected void configure(HttpSecurity http) throws Exception
{
//csrf is disabled for the moment
//http.csrf().disable();
//authorized requests
http.authorizeRequests()
.antMatchers("/api/users/**").permitAll()
.antMatchers(HttpMethod.OPTIONS , "/*/**").permitAll()
.antMatchers("/login").permitAll()
.anyRequest().authenticated();
//handling authentication exceptions
http.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint);
//login configuration
http.formLogin()
.loginProcessingUrl("/login")
.successHandler(authenticationSuccessHandler);
http.formLogin()
.failureHandler(authenticationFailureHandler);
//logout configuration
http.logout()
.logoutUrl("/logout")
.logoutSuccessHandler(logoutSuccessHandler);
//CORS configuration
http.addFilterBefore(corsFilter, ChannelProcessingFilter.class);
//CSRF configuration
http.csrf().requireCsrfProtectionMatcher(
new AndRequestMatcher(
// Apply CSRF protection to all paths that do NOT match the ones below
// We disable CSRF at login/logout, but only for OPTIONS methods to enable the browser preflight
new NegatedRequestMatcher(new AntPathRequestMatcher("/login*/**", HttpMethod.OPTIONS.toString())),
new NegatedRequestMatcher(new AntPathRequestMatcher("/logout*/**", HttpMethod.OPTIONS.toString())),
new NegatedRequestMatcher(new AntPathRequestMatcher("/api*/**", HttpMethod.GET.toString())),
new NegatedRequestMatcher(new AntPathRequestMatcher("/api*/**", HttpMethod.HEAD.toString())),
new NegatedRequestMatcher(new AntPathRequestMatcher("/api*/**", HttpMethod.OPTIONS.toString())),
new NegatedRequestMatcher(new AntPathRequestMatcher("/api*/**", HttpMethod.TRACE.toString()))
)
);
// CSRF tokens handling
http.addFilterAfter(new CSRFTokenResponseCookieBindingFilter(), CsrfFilter.class);
}
}
The problem is in the front side and the angular 4 configuration, the CSRF documentation is so poor and there is no full example of CSRF implementation in the Internet.
So below is my login service:
#Injectable()
export class LoginService {
private loginUrl = 'http://localhost:51030/login';
constructor(private http: Http) {}
preFlight() {
return this.http.options(this.loginUrl);
}
login(username: string , password: string) {
let headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded');
let options = new RequestOptions({headers: headers});
let body = "username="+username+"&password="+password;
return this.http.post(this.loginUrl , body , options);
}
}
And in the login component I execute the option request in the ngOnInit life cycle hook:
#Component({
templateUrl: './login-layout.component.html'
})
export class LoginLayoutComponent implements OnInit {
credentials = {username: '' , password: ''};
constructor(private loginService: LoginService){}
ngOnInit() {
this.loginService.preFlight()
.subscribe();
}
login() {
this.loginService.login(this.credentials.username , this.credentials.password)
.subscribe(
response=>{
console.log(response) ;
},error=>{
console.log(error);
}
);
}
}
The preflight goes well and I get the 200 OK status on the options request plus a temporary JSEEIONID and the XSRF-TOKEN Cookie.
So in my app module I added this as said in the angular docs:
{
provide: XSRFStrategy,
useValue: new CookieXSRFStrategy('XSRF-TOKEN', 'X-XSRF-TOKEN')
},
BUT, when I try to execute a POST request with the credentials or any request to the back I got 403 Forbidden: "Could not verify the provided CSRF token because your session was not found."
So Please how can I solve this, can any one point me to right direction cause I have no clue on how to make this work!!
And Thanks!!!
To solve the csrf problem between spring security and angular, you have to do that.
In SecurityConfiguration (WebSecurityConfig),replace http.csrf().disable(); by
http.csrf()
.ignoringAntMatchers ("/login","/logout")
.csrfTokenRepository (this.getCsrfTokenRepository());
}
private CsrfTokenRepository getCsrfTokenRepository() {
CookieCsrfTokenRepository tokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse();
tokenRepository.setCookiePath("/");
return tokenRepository;
{
the default angular csrf interceptor does not always work.So you have to implement your own interceptor.
import {Injectable, Inject} from '#angular/core';
import {HttpInterceptor, HttpXsrfTokenExtractor, HttpRequest, HttpHandler,
HttpEvent} from '#angular/common/http';
import {Observable} from "rxjs";
#Injectable()
export class HttpXsrfInterceptor implements HttpInterceptor {
constructor(private tokenExtractor: HttpXsrfTokenExtractor) {
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
let requestMethod: string = req.method;
requestMethod = requestMethod.toLowerCase();
if (requestMethod && (requestMethod === 'post' || requestMethod === 'delete' || requestMethod === 'put')) {
const headerName = 'X-XSRF-TOKEN';
let token = this.tokenExtractor.getToken() as string;
if (token !== null && !req.headers.has(headerName)) {
req = req.clone({headers: req.headers.set(headerName, token)});
}
}
return next.handle(req);
}
}
And finally add it in your providers (app.module.ts)
providers: [{ provide: HTTP_INTERCEPTORS, useClass: HttpXsrfInterceptor, multi: true }]
Think about putting in your imports.
HttpClientXsrfModule.withOptions({
cookieName: 'XSRF-TOKEN',
headerName: 'X-CSRF-TOKEN'
}),
I am surprised that you are doing so much work for CSRF and CORS as Spring Security and Angular have support built in. Spring Security has CSRF enabled by default.
The spring security manual has good documentation about configuring csrf:
https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#csrf
And googling for "Angular 2 Spring Security csrf" gives several examples (and also how I found your post). Here is one:
https://medium.com/spektrakel-blog/angular2-and-spring-a-friend-in-security-need-is-a-friend-against-csrf-indeed-9f83eaa9ca2e
I am using GWTUplaod in my application which is working fine if I don't use cross domain.But it is not working correctly in cross domain scenario.
Let me explain,
GWT Server is at IP address 5.5.5.10 and GWT Client is at IP address 5.5.5.12 , earlier while uploading I was getting error in request due to cross domain then I override servlet doPost and doGetMethod
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
try {
FlowContextManager.getInstance().setFlowId(FlowContextManager.getNextFlowId());
processCrossDomainHeaders(request, response);
super.doGet(request, response);
} catch (Exception e) {
logger.error(e);
} finally {
FlowContextManager.getInstance().setFlowId("");
}
}
#Override
protected final void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException,
ServletException {
try {
FlowContextManager.getInstance().setFlowId(FlowContextManager.getNextFlowId());
processCrossDomainHeaders(request, response);
super.doPost(request, response);
} catch (Exception e) {
logger.error(e);
} finally {
FlowContextManager.getInstance().setFlowId("");
}
}
public void processCrossDomainHeaders(HttpServletRequest request, HttpServletResponse response) {
HttpServletResponse resp = response;
HttpServletRequest req = request;
String header = req.getHeader("Origin");
if (header != null) {
resp.addHeader("Access-Control-Allow-Origin", header);
}
resp.addHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
header = req.getHeader("Access-Control-Request-Headers");
if (header != null) {
resp.addHeader("Access-Control-Allow-Headers", header);
}
resp.addHeader("Access-Control-Max-Age", "100");
}
#Override
protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.addHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));
resp.addHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
String header = req.getHeader("Access-Control-Request-Headers");
resp.addHeader("Access-Control-Allow-Headers", header);
resp.addHeader("Access-Control-Max-Age", "100");
super.doOptions(req, resp);
}
Now my GWTUploadServlet is extending this abstract servlet.
In my web.xml I have specified following entries
<servlet>
<servlet-name>uploadServlet</servlet-name>
<!-- This is the default servlet, it puts files in session -->
<servlet-class>com.drishti.ameyo.webclient.server.WebClientUploadServlet</servlet-class>
<init-param>
<param-name>corsDomainsRegex</param-name>
<param-value>.*</param-value>
</init-param>
</servlet>
I have referred following link
http://code.google.com/p/gwtupload/issues/detail?id=187
Request is getting successful but I am getting following error on browser console.
Blocked a frame with origin "http://10.10.10.192:8888" from accessing a frame with origin "http://10.10.10.250:8888". Protocols, domains, and ports must match. FormPanelImpl.java:32
onSubmitComplete: null SuperDevModeLogger.java:71
onSubmitComplete exception parsing response: SuperDevModeLogger.java:71
com.google.gwt.xml.client.impl.DOMParseException: Failed to parse: error on line 1 at column 1: Document is empty
at createStackTrace
at fillInStackTrace_1
at fillInStackTrace
at $fillInStackTrace
at Throwable_1
at Exception_1
at RuntimeException_1
at DOMException_1
at DOMParseException_0
at throwDOMParseException
at parseImpl_0
at $parse_3
at parse_3
at onSubmitComplete_0
at $dispatch_22
at dispatch_23
at dispatch
at dispatchEvent_1
I didn't get some good solution on it.Please help for it.
I got this problem while trying to access REST web service using GWT client.
I inspect the chrome page then i got the following error from console
XMLHttpRequest cannot load http://localhost:8080/RestWeb/webresources/generic/get. Origin http://127.0.0.1:8888 is not allowed by Access-Control-Allow-Origin.
Following is my client side code
public void onModuleLoad() {
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET,
"http://localhost:8080/RestWeb/webresources/generic/get");
builder.setCallback(new RequestCallback() {
#Override
public void onResponseReceived(Request request, Response response) {
Window.alert("onResponseReceived");
}
#Override
public void onError(Request request, Throwable exception) {
}
});
builder.setHeader("Content-Type",
"text/plain,application/json,text/xml");
builder.setHeader("Access-Control-Allow-Methods",
"PUT, GET, POST, DELETE, OPTIONS");
builder.setHeader("Access-Control-Allow-Headers", "Content-Type");
builder.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:8888");
try {
builder.send();
} catch (RequestException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
My server side code is :
#Path("generic")
#WebService
public class GenericResource {
#Context
private UriInfo context;
#Context
private HttpServletResponse response;
private String content = "content";
/**
* Creates a new instance of GenericResource
*/
public GenericResource() {
}
#GET
#Path("/get")
#Produces("application/json,text/plain")
public String getXml() {
System.out.println("GET");
//response.addHeader(content, content);
return this.content + " from get method";
}
}
I tried in different ways to get answer. Please help me.
You need to change your server code to support CORS.
One option is a filter:
public class CorsFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (request.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(request.getMethod())) {
// CORS "pre-flight" request
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
response.addHeader("Access-Control-Allow-Headers", "Content-Type");
response.addHeader("Access-Control-Max-Age", "1800");//30 min
}
filterChain.doFilter(request, response);
}
}
The web.xml needs adding the following too:
<filter>
<filter-name>cors</filter-name>
<filter-class>com.xxx.CorsFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>cors</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Since it's an old question, if one is facing similar issues today - he or she may want to consider using a nice "CORS Filter" that handles all CORS stuff for you in a completely transparent way. Here's the link
i'have two web appli, tapestry appli and a simple web appli(servelt). in tapestry appli , i have a form, and when it'll be sent, i call a httpClient for sending some informations to author appli using apache's httpClient. like this
void onSubmitFromForm() {
try {
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost("http://localhost:8080/appli2/recep");
post.setHeader("referer", "http://localhost:9090/app1/start");
List<NameValuePair> param = new ArrayList<NameValuePair>();
param.add(new BasicNameValuePair("_data", getData());
post.setEntity(new UrlEncodedFormEntity(param));
HttpResponse response = client.execute(post);
response ?????
} catch (Exception e) {
e.printStackTrace();
}
}
And in my servelt recep of the simple web appli(2) i do the same like below
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
try {
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(request.getHeader("referer"));
post.setHeader("p",getP());
client.execute(post);
} catch (Exception e) {
e.printStackTrace();
}
}
So, my recep reviev data from my form but it'cannot response it, i'would that tapersty appli could recieve the param 'P' from the simple web appli ?
thanks
If I'm correct you want your tapestry application to POST some form data received from a form submit within Tapestry to a servlet running on another application.
If this is what you want then what is missing is the haneling of the request and constructing a response in your servlet. Because both your tapestry page and your servlet are POST'ing meaning neither constructs a response for your HttpClient to deal with.
In your servlet you could:
public void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
response.setContentType("text/plain");
PrintWriter out = response.getWriter();
out.println(getP());
out.close();
}
And deal with the response in your tapesty form handler.