JAX-RS enabling CORS (Access-Control-Allow-Origin) on Glassfish 4 - glassfish

I am working in JAVA EE7, JAX-RS 2.0 Glassfish 4 is my SERVER.
I Want to work on CORS to enable Ajax Requests comming out of my domain.
I know that I need to make my server enabling it. And I did it in PHP. like the following code:
<?php header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Authorization");
but when I tried to do the same thing I always get an error message like that
"this is a screenshot".
So I've tried to modify the sever http response with many ways...
And this is my code , server side , I used a filer/provider:
#Provider
#CORSBinding
public class Filter implements ContainerRequestFilter{
#Override
public void filter(ContainerRequestContext request) throws IOException {
request.getHeaders().add("Access-Control-Allow-Origin", "*");
request.getHeaders().add("Access-Control-Allow-Headers", "Authorization");
if (request.getMethod().equals("OPTIONS")) {
System.out.println("OPTIONS is requested!!!!!!!!!!!!!");
}
if (request.getMethod().equals("GET")) {
System.out.println("GET is requested!!!!!!!!!!!!!");
}
if (request.getMethod().equals("POST")) {
System.out.println("POST is requested!!!!!!!!!!!!!");
}
if (request.getMethod().equals("DELETE")) {
System.out.println("DELETE is requested!!!!!!!!!!!!!");
}
if (request.getMethod().equals("PUT")) {
System.out.println("PUT is requested!!!!!!!!!!!!!");
}
}
}
But it seems like all blocked by a "firewall security" provided by Glassfish4 server.
here is my simple code javascript:
<script>
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://127.0.0.1:8080/CV/api/v2/posts");
xhr.setRequestHeader('Authorization', 'a');
xhr.send();
</script>
I even added an other filter using the #Prematching annotation to update the request from OPTIONS TO POST ... but I always lose my headers that I have sent within it (I mean within POST request).
#Provider
#PreMatching
public class HttpMethodOverrideEnabler implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
containerRequestContext.setMethod("POST");
containerRequestContext.getHeaders().add("Access-Control-Allow-Origin", "*");
containerRequestContext.getHeaders().add("Access-Control-Allow-Headers","Authorization");
containerRequestContext.getHeaders().add("Access-Control-Allow-Headers","Authorization");
String override = containerRequestContext.getHeaders().getFirst( "X-HTTP-Method-Override");
if (override != null) {
containerRequestContext.setMethod(override);
}
}
I knew that Glassfish3 had not the support for CORS and ("https://java.net/jira/browse/GLASSFISH-16049) they said that they will fix it with JEE7.
This is the whole story...
so how can I do the CORS with this JEE7 using Glassfish server and JAX-RS2.
Thanks in advance.

Use ContainerResponseFilter not ContainerRequestFilter as you want to add those headers into response and not to the request. For example:
#Provider
#Priority(Priorities.HEADER_DECORATOR)
public class AccessControlResponseFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
final MultivaluedMap<String,Object> headers = responseContext.getHeaders();
headers.add("Access-Control-Allow-Origin", "*");
headers.add("Access-Control-Allow-Headers", "Authorization, Origin, X-Requested-With, Content-Type");
headers.add("Access-Control-Expose-Headers", "Location, Content-Disposition");
headers.add("Access-Control-Allow-Methods", "POST, PUT, GET, DELETE, HEAD, OPTIONS");
}
}

You have to use the 2 *filters* the First because Chrome and other Browsers modify the headers for security purpose, and the second is to add the headers to response. So use ContainerResponseFilter and ContainerRequestFilter. it works fine with me Good luck!

Related

How can I provide my custom OAuth2LoginAuthenticationProvider in spring boot

I am trying to setup OAuth2 login in spring boot, every thing is working good in my dev environment, however when I deploy it on production behind the Apache Http server using proxy configuration, authentication fails on Invalid Redirect URI check.
As suggested in some other post I already tried
1. use-forward-headers: true
2. Rewriting the request redirect URI
with no luck.
So I decided to hook my own custom OAuth2LoginAuthenticationProvider so that I can override this check.
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Value("${baseUrl}")
private String domainPath;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(new MyCustomFilter(domainPath), OAuth2LoginAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().authenticated().and()
.logout().logoutSuccessUrl("/")
.and()
.oauth2Login().userInfoEndpoint().customUserType(CmmOAuth2User.class, "custom");
}
#Bean
public MyOAuth2AuthenticationProvider authenticationProvider() {
MyOAuth2AuthenticationProvider authProvider
= new MyOAuth2AuthenticationProvider();
return authProvider;
}
#Autowired
public void configureProviderManager(ProviderManager providerManager) {
providerManager.getProviders().add(0,authenticationProvider());
}
#Bean
public ProviderManager authenticationManager() {
List<AuthenticationProvider> authProviderList = new ArrayList<AuthenticationProvider>();
authProviderList.add(0,authenticationProvider());
ProviderManager providerManager = new ProviderManager(authProviderList);
return providerManager;
}
}
My custom MyOAuth2AuthenticationProvider is not being called.

Server uses Cors but UI still gets allow-origin error

Hello i am trying to issue a http get request to a .NET Core Console App from my Angular 2 frontend and i get the following error:
Access to XMLHttpRequest at 'http://127.0.0.1:9300/api/getusers' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
For me it is curious since i have enabled CORS on the server side as you can see below in the Startup class.
Startup
public class Startup {
public Startup(IConfiguration configuration) {
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services) {
services.AddOptions();
services.AddMvc();
}
public IConfiguration Configuration;
public void Configure(IApplicationBuilder app) {
Console.WriteLine("request delievered");
Debug.WriteLine("Entered Server !");
app.UseMvc();
app.UseCors(x => { x.AllowAnyHeader(); x.AllowAnyOrigin();x.AllowAnyMethod(); });
}
}
I make the request from the UI like this:
#Injectable()
export class UserService{
private static baseUrl:string="http://127.0.0.1:9300/api";
constructor(private http:HttpClient) {
}
getClientsAsync():Promise<User[]>{
let route=UserService.baseUrl+"/getusers";
var data=(this.http.get(route) //should i have some headers here?
.map(resp=>resp)
.catch(err=>
Observable.throwError(err)
) as Observable<User[]>).toPromise<User[]>();
return data;
}
}
P.S I have tried with Postman and the request works ,however here in the angular 2 i have not included any headers for my http.get method.Could this be the problem ?
You need to put UseCors before UseMvc.
public void Configure(IApplicationBuilder app) {
Console.WriteLine("request delievered");
Debug.WriteLine("Entered Server !");
app.UseCors(x => { x.AllowAnyHeader(); x.AllowAnyOrigin();x.AllowAnyMethod(); });
app.UseMvc();
}
This is because UseCors adds a middleware (as does UseMvc), and middleware are executed in order from top to bottom. So the request never gets to the CORS middleware.

In WCF how do I remove the 404 response body?

I have a WCF service configured and I'm using routing to configure it. Everything is working the way I want it, except the 404 messages have a body stating Service Endpoint not found.
I'd like the 404 to have an empty response body.
Here is my route registration:
public class Global : HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
private void RegisterRoutes(RouteCollection routes)
{
routes.Add(new ServiceRoute("RootService", new WebServiceHostFactory(), typeof(ServiceProvider)));
}
Here is my service class:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
[ServiceContract]
public class ServiceProvider
{
[WebGet]
public Test ValidUrl()
{
return new Test();
}
}
How do I make the response for this url http://localhost/RootService have an empty 404 body?
I found a few ways to do this and I've listed two below. They key is having the UriTemplate set as *. This makes the method match all routes that aren't explicitly matched otherwise.
[WebGet(UriTemplate="*")]
public void ErrorForGet()
{
throw new WebFaultException(HttpStatusCode.NotFound);
}
I don't like this way as well, but it works:
[WebGet(UriTemplate="*")]
public void ErrorForGet()
{
WebOperationContext.Current.OutgoingResponse.SetStatusAsNotFound();
}
Both of these methods have overloads that take a string as a message to provide to the requesting client. The WebFaultException needs to be like this going that route though: throw new WebFaultException<string>("Resource not found", HttpStatusCode.NotFound);

Websphere pre-login to j_security_check

I am using Websphere with j_security_check and I have a working login filter with CONFIDENTIAL and SSL settings. Due to some complex requirements, I need to process the j_username variable before performing j_security_check.
From one of the answers found here, it was said that this pre-login processing cannot be done. However, I noted that the previous asker was using Tomcat, while I am using Websphere. I found that there is a solution for my problem over here but it seems that everytime I try to login, I receive a "The website cannot display the page. The website has a programming error."
I tried troubleshooting by checking if the syntax was correct. Found some inconsistencies like and corrected them as best I could. However, I still keep getting the same error.
Could someone throw me in the right direction? I can provide further info but they are mostly similar to the second link. The only protected folder is in \protected\ and the .java servlet is located in \WEB-INF\classes.
Thank you.
In case anyone is interested, the results are here:
For \WEB-INF\web.xml
<filter id="Filter_1">
<filter-name>LoginFilter</filter-name>
<filter-class>com.myloginfilter.MyLoginFilter</filter-class>
<description>Performs pre-login operation</description>
</filter>
<filter-mapping>
<filter-name>LoginFilter</filter-name>
<url-pattern>/j_security_check</url-pattern>
</filter-mapping>
For \WEB-INF\classes\com\myloginfilter\MyLoginFilter.class
public class MyLoginFilter implements Filter {
protected FilterConfig filterConfig;
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
public void destroy() {
this.filterConfig = null;
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException {
chain.doFilter(new MyRequestWrapper((HttpServletRequest) request), response);
}
public static class MyRequestWrapper extends HttpServletRequestWrapper {
public MyRequestWrapper(HttpServletRequest request) {
super(request);
}
#Override
public String getParameter(String name) {
String username= getRequest().getParameter("j_username");
if ("j_password".equals(name) && "admin".equals(username)) {
username = "administrator";
return username;
}
return super.getParameter(name);
}
}
}
To compile it, use Javac with the command:
javac -cp servlet-api-2.3.jar MyLoginFilter.class

Issue with adding multiple cookies to Response in WCF service

I've managed to add multiple cookies in the WCF service outgoing response by adding "Set-Cookie" attribute in the response header. It works great and the cookie is available in all subsequent requests only if there is one cookie but not for multiple cookies.Please refer my below implementation. I'm adding the cookies into the response header by implementing IDispatchMessageInspector interface in order to add cookies in all WCF service method calls if there any pending cookies to be updated in the response.
Sample of Cookies output in the response header and request header
1 Cookie: foo=testcookie1; path=/ --> available in all the subsequent request calls
2 or more cookies: foo=testcookie1; path=/;, foo2=testcookie2; path=/;, foo3=testcookie3; path=/; --> --> only the first cookie available in all the subsequent request calls but not others
For example:
after the setting the cookies, my response header will look like Set-Cookie: foo1=testcookie1;,foo2=testcookie2;, foo3=testcookie3;. If I make another request then the request header cookie contains only foo1=testcookie1; but not these cookies foo2=testcookie2; foo3=testcookie3;. This is where the issue comes. If I set more than one cookie in the response header then it always takes only the first cookie in the subsequent request call.
Please help me to resolve this issue. Thanks in advance for your kind replies.
IMPLEMENTATION
public class CookieManagerServiceBehaviorAttribute : Attribute, IServiceBehavior
{
#region IServiceBehavior Members
public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
return;
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher channelDispatch in serviceHostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher endpointDispatch in channelDispatch.Endpoints)
{
endpointDispatch.DispatchRuntime.MessageInspectors.Add(CookieManagerMessageInspector.Instance);
}
}
}
public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
return;
}
#endregion
}
public class CookieManagerMessageInspector : IDispatchMessageInspector
{
private static CookieManagerMessageInspector instance;
private CookieManagerMessageInspector() { }
public static CookieManagerMessageInspector Instance
{
get
{
if (instance == null)
{
instance = new CookieManagerMessageInspector();
}
return instance;
}
}
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
return null;
}
public void BeforeSendReply(ref Message reply, object correlationState)
{
HttpResponseMessageProperty httpResponse;
if (!reply.Properties.ContainsKey(HttpResponseMessageProperty.Name))
{
reply.Properties.Add(HttpResponseMessageProperty.Name, new HttpResponseMessageProperty());
}
httpResponse = (HttpResponseMessageProperty)reply.Properties[HttpResponseMessageProperty.Name];
foreach (Cookie cookie in RenderContext.Current.PendingCookies)
{
if (cookie.Expires > DateTime.Now)
httpResponse.Headers.Add(HttpResponseHeader.SetCookie, "{0}={1}; expires={2}".StringFormat(cookie.Name, cookie.Value, DateTime.Now.AddYears(1).ToUniversalTime()) + ";");
else
httpResponse.Headers.Add(HttpResponseHeader.SetCookie, "{0}={1};".StringFormat(cookie.Name, cookie.Value));
}
}
}
While building a web proxy I ran into the same problem. I needed to relay the Set-Cookie header from the target HttpWebResponse to the proxy HttpListenerResponse. If there were multiple cookies in the Set-Cookie header then only the first one would register in the browser.
I was able to get it to work when I iterated through the set of values of the header (or in your case the collection of Cookies) and used the response.AppendHeader(header, value) form.
string[] cookies = response.Headers.GetValues("Set-Cookie");
foreach (string value in cookies)
clientResponse.AppendHeader("Set-Cookie", value);
So in your case I would change the end of your code to:
if (cookie.Expires > DateTime.Now)
httpResponse.AppendHeader(HttpResponseHeader.SetCookie, "{0}={1}; expires={2}".StringFormat(cookie.Name, cookie.Value, DateTime.Now.AddYears(1).ToUniversalTime()) + ";");
else
httpResponse.AppendHeader(HttpResponseHeader.SetCookie, "{0}={1};".StringFormat(cookie.Name, cookie.Value));