SpringBoot - Angular 5 - CSRF - spring-boot

Iam lost now and need some help.
I have a
SpringBoot Server with SpringSecurtiy 4.3.
Angular 5 App
And want to enable CSRF protection since it should be enabled on both by default (says the docs)
:Its NOT!
On SpringBoot I need to add these security configs:
http
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
On Angular I need to add these Modules:
imports: [
...,
HttpClientModule,
HttpClientXsrfModule, //(!)
...
Bottom line the server send the XRSF-TOKEN in each response.
-But a diffrent on each one. Is that correct? I expected to be the same on a client session.
-Main problem here is that Angular5 still didnt use the XRSF-TOKEN in its post calls (e.g.). It dont set a X-XSRF-TOKEN in its requests.
What am I doing wrong or missing?

I had this same problem and I think it is a regression due to version 5 of angular.
Until this is fixed you can add your own 'X-XSRF-TOKEN' header as I did.
constructor(private http: HttpClient, private tokenExtractor: HttpXsrfTokenExtractor) {
}
then extract manually a token
const token = this.tokenExtractor.getToken() as string;
and add it to the header
this.http.post<any>(url, body, {headers: new HttpHeaders().set('X-XSRF-TOKEN', token)})
Houssem

Related

Django drf-spectacular with FirebaseBackend auth

To give as much context as possible; I have two problems while using drf-spectacular to build my API documentation;
With my default configuration, I cannot even load the documentation's page because I have a custom auth backend (using firebase_admin 5.2.0), the swagger (or ReDoc) are part of my REST API, therefore, would have to pass a valid token to load the page allocated in the documentation's endpoint (which is not possible from a browser).
Second, and most importantly, I am not able to configure my custom firebase auth with drf-spectacular to implement a Swagger authentication method to execute against my API endpoints. I would be just fine having the possibility to add a token in the Swagger doc, do not need to have all Firebase auth credentials, URLs, and flow.
api/urls.py
router = routers.DefaultRouter()
urlpatterns = [
path('api/schema/', SpectacularAPIView.as_view(), name='schema'),
path('api/schema/swagger/', SpectacularSwaggerView.as_view(), name='swagger'),
path('api/schema/redoc/', SpectacularRedocView.as_view(), name='redoc'),
# _____________________FIREBASE AUTH ______________________
path('api-auth/', include('rest_framework.urls')),
path('', include(router.urls)),
settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'auth.backends.FirebaseBackend',
],
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
}
I have unsuccessfully tried adding many different configurations to my SPECTACULAR_SETTINGS.
Thanks in advance!!
By default spectacular uses 'SERVE_PERMISSIONS': ['rest_framework.permissions.AllowAny'], which should allow opening the swagger page even if not authenticated. Maybe FirebaseBackend bails hard which prevents you ever getting to AllowAny. Try this to take Firebase out of the equation for the schema views:
SPECTACULAR_SETTINGS = {
...
'SERVE_PERMISSIONS': ['rest_framework.permissions.AllowAny']
'SERVE_AUTHENTICATION': [],
}
You need to write an OpenApiAuthenticationExtension for Firebase as it is not part of the spectacular at the moment.

Vuejs Axios POST request gets HTTP422 error from Laravel backend

Hi I am using Vuejs in the frontend and Laravel in the backend. The role of Laravel is handling the API only. The frontend and backend are separated, i.e. I am not using Vuejs in Laravel's resource/js folder.
Now I am sending Axios POST request from Vuejs to Laravel. All the form input values are prevalidated using HTML5 required attribute. And when I console.log the request data, it shows all the fields filled.
In Vue file:
const data = {
name: this.name,
gender: this.gender,
mobile_no: this.mobile_no,
image: this.userImage
};
console.log("Request data . . . .", data);
const response = await this.axios
.post(`${this.AppURL}/admin/user/create`, data, {
headers: {
"Content-Type": "multipart/form-data"
}
})
.then(() => {
console.log("Success. . . . ")
alert("Successfully Driver Added");
})
.catch(error => console.log(error));
And in Laravel, the request is passed through some validation. It's a simple validation to check if all the fields are filled.
I am also using JWTAuth package for the authentication, and the token is generated by it.
It's too much code to write them all the way down here. But I am sure you can understand what I mean.
What I am getting as a response is this
POST http://localhost:8000/api/admin/user/create 422 (Unprocessable Entity)
The actual result I am expected to get is either success or some errors that is according to some if conditions in validation or token check.
I tried to figure out where this error might come from. What I think at the moment is this could be due to the absence of csrf_token in the POST request. As I'm sending the request outside Laravel, csrf_token is missing in the form. I am not 100% sure though about this.
So my question is:
How can I include csrf_token in Axios POST request, when I send it from outside Laravel.
If this 422 error is not related with csrf_token, what could be causing this? Any previos experiences like min? and any solutions for this?
Thanks in advance for your help.
Please, modified catch block as #Jack suggested:
.catch(error => {
console.log("ERRRR:: ",error.response.data);
});
Now you can get errors and handle errors in the catch block.
.catch(function (error) {
console.log(error.response.data.errors);
});
please use this code I hope it work's.
I was also facing the same issue, i think it is due to some Headers missing in your Api request from vue.js. here some tips which may helps you to solve this issues.
Make sure that you are protecting your Api Routes or not(by sanctum or something else). If you are protecting , then make make sure that you are sending authentications token in headers.
Second make sure that your request(axios or jwt) should contained valid data, if your are sending images or files etc make sure how can we send them.
First, get request and check in laravel by dd($erquest->all()); if you are geeting data then validate, it is possible that laravel request doesnt contained your sending data..
These errors may be caused due to follow reasons, ensure the following steps are followed.
To connect the local host with the local virtual machine(host).
Here, I'am connecting http://localhost:3001/ to the http://abc.test
Steps to be followed:
We have to allow CORS, placing Access-Control-Allow-Origin:* in header of request may not work. Install a google extension which enables a CORS request.
Make sure the credentials you provide in the request are valid.
Make sure the vagrant has been provisioned. Try vagrant up --provision
this make the localhost connect to db of the homestead.
Just click on the preview tab within network section in the dev tool, you are going to see the actual error message.

JWT with Angular and SpringBoot

I want to integrate a JWT authentication in my current Angular application which is connected to a spring boot backend.
I looked through quiet a lot of tutorials, but most of them did not fit, since they were connected to Auth0. I want to handle the usermanagement by myself.
I found this example:
Angular: https://medium.com/#juliapassynkova/angular-springboot-jwt-integration-p-1-800a337a4e0
Spring Boot: https://medium.com/#nydiarra/secure-a-spring-boot-rest-api-with-json-web-token-reference-to-angular-integration-e57a25806c50
Unfortunately, this Angular Frontend is Angular 4 and I'm using Angular 6 already. They use the 'angular2-jwt' which is not compatible with Angular 6. I have to use 'auth0/angular-jwt'.
My problem is, that after I use my login form, the browser opens again a login popup to login the backend. But even with the right credentials, it doesn't work. I'm guessing, that some credentials are missing in the request. In the app.module.ts are 2 old angular2-jwt code, which i don't know how to upgrade it to auth0/angular-jwt
export function authHttpServiceFactory(http: Http) {
return new AuthHttp(new AuthConfig({
headerPrefix: 'Bearer',
tokenName: TOKEN_NAME,
globalHeaders: [{'Content-Type': 'application/json'}],
noJwtError: false,
noTokenScheme: true,
tokenGetter: (() => localStorage.getItem(TOKEN_NAME))
}), http);
}
and
providers: [
{provide: AuthHttp, useFactory: authHttpServiceFactory, deps: [Http]},
]
Can someone help me with this issue. May be I'm wrong with my guessing and it could be something else?
A side note; I just changed my frontend but trying to connect to the backend from the example. If I'm using both front- and backend from the example, its working fine.
I have passed successful migration from angular2-jwt to auth0/angular-jwt several months ago. What you have to keep in mind while doing so is:
auth0/angular-jwt uses new angular HttpClient library, so if you want to use so, you have to migrate all your application to it (I suggest doing so anyway, new library is quite amazing)
new angular-jwt uses HttpInterceptors - this allows you to attach JWT directly to HttpClient filters chain. So you don't have to migrate your code above. You have to remove it completely and replace with interceptor initialization: (copy-paste from auth0/angular-jwt documentation):
import { JwtModule } from '#auth0/angular-jwt';
import { HttpClientModule } from '#angular/common/http';
export function tokenGetter() {
return localStorage.getItem('access_token');
}
#NgModule({
bootstrap: [AppComponent],
imports: [
// ...
HttpClientModule,
JwtModule.forRoot({
config: {
tokenGetter: tokenGetter,
whitelistedDomains: ['localhost:3001'],
blacklistedRoutes: ['localhost:3001/auth/']
}
})
]
})
export class AppModule {}
Remember to apply this code in your root module - then use your HttpClient without any changes and interceptors will apply JWT automatically. In case of problems - blame whitelistedDomains/blacklistedRoutes. These fields are very poorly implemented at the moment and are causing problems with regular expressions etc.
As migration is not straightforward, and took me a lot of time, feel free to ask about it. There's high probability, that I'll know the answers.

How to configure OPTIONS request in CORS to Access-Control-Allow-Origin with ASP.NET Web API

I'm having an issue trying to get a token from my server on an Angular 5 project. My POST request is never sent and the server returns 400 Bad Request and shows the following in the console:
My understanding is that I need to configure the OPTIONS request in CORS to allow the cross-origin request, but I feel like I've tried every solution there is out there without any success.
As far as what I have tried so far, in my Web.config I have this:
And I enabled CORS globally in my WebApiConfig.cs:
I even implemented the solution suggested at https://www.stevefenton.co.uk/2012/11/using-cors-with-asp-net-web-api/
Here is the call I am making in my Angular 5 project:
userAuthentication(userDetails: LoginUser): Observable<LoginUser> {
var data = "username=" + userDetails.username + "&password=" + userDetails.password + "&grant_type=password";
var reqHeader = new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded', 'No-Auth': 'True' });
return this.http.post<LoginUser>(this._baseUrl + 'Token', data, { headers: reqHeader })
.pipe(
catchError(this.handleError)
)
}
When I make the call using POSTMAN, everything runs smoothly and I get my access_token.
I've managed to resolve this issue. I needed to add Microsoft.Owin.Cors with Microsoft.AspNet.Cors and Microsoft.AspNet.WebApi.Cors.
I then had to add app.UseCors(CorsOptions.AllowAll); to my Startup.cs file:
…and remove the customHeaders from between the system.webserver tags in Web.config:
All is running smoothly now.
Note: It's important to note that when enabling CORS on your WebApiConfig.cs, if you have followed the previous steps I have shown, you must enable it like this:
…and not like this:
If you do, you will get an error stating your header contains multiple values and therefore will deny your Origin access.

SignalR responses overwriting headers

I've built a simple SignalR hub that lives within a WebAPI service, I've included all the required CORS attributes on both WebAPI and SignalR. My WebAPI endpoints are all working as expected but SignalR isn't.
I've tried all I can think of and all I can find online but nothing works, I already tried this answer, and this other to no solution.
My SignalR extension method looks like this
public static IAppBuilder UseSignalrNotificationService(this IAppBuilder app)
{
var config = new HubConfiguration();
config.Resolver = new HubDependencyResolver();
config.EnableDetailedErrors = true;
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR(config);
return app;
}
And I even tried adding the response headers on all requests using the Web.config but I allways get the same error:
XMLHttpRequest cannot load https://MyApplicationServer/notifications/signalr/negotiate?clientProtocol=1.5&access_token=&connectionData=. A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true. Origin 'MyOriginService' is therefore not allowed access. The credentials mode of an XMLHttpRequest is controlled by the withCredentials attribute.
After more research and fiddling with the server side of the problem, I ran into this answer and found the error to be with the client side of the request. according to this GitHub issue, the "withCredentials" parameter of the request is always set to 'true'. The solution was to call on the client the start method as follows:
$.connection.hub.start({ withCredentials: false }).done(function () { //... }
Are you changing the request somewhere with some kind of global interceptor? For some reason, the XMLHttpRequest starts with withCredentials:true and this is forbidden when the Access-Control-Allow-Origin is set to *.
What about setting the 'Access-Control-Allow-Origin' to 'http://MyApplicationServer'? It's safer than * and will remove your problem at source.

Resources