Django not returning CSRF Token - wpf

I implemented an application using C# and Django, and my problem is that when I login in the client the server returns everything right, the sessionid and everything but the csrf token.
I have it on my settings file in middleware_classes. Is this because im accessing the server directly through its ip address?
My django Login function
class loginMobile(GenericAPIView):
serializer_class = loginSerializer
def post(self, request):
try:
email = request.DATA.get('email')
password = request.DATA.get('password')
user_django = authenticate(username=email, password=password)
login(request, user_django)
return Response({'success': True})
except:
return Response({'success': False})
my C# request:
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
// Get the response stream
StreamReader reader = new StreamReader(response.GetResponseStream());
if (response.Cookies != null && response.Cookies.Count != 0)
{
this.cookie_col = response.Cookies;
this.cookies = new List<Cookie>();
foreach (Cookie c in response.Cookies)
{
this.cookies.Add(c);
if (c.Name.Equals("csrftoken"))
this.csrf_token = c.Value;
}
}
}
In "response.cookies" I only get the "sessionid" not the "csrftoken"
Also this happening when I hosted the appplication in a server, it works like a charm on my local machine

So I figure out how to work around my problem,
I forced django to return the csrf token like this:
return Response({'success': True, 'csrf':csrf(request)})

Related

Why does my Flask React.js session not work?

I'm making the login for a app in react with the backend in flask but the session is not working.
The flask app is running in a remote server on pythonanywhere and I'm testing the react app on my localhost:3000
Here's the code for the flask app:
app = Flask(__name__)
app.config["SESSION_PERMANENT"] = True
app.config["SESSION_TYPE"] = "filesystem"
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(hours=5)
Session(app)
CORS(app, supports_credentials = True, resources={r"/webapp/*": {"origins": "http://localhost:3000/"}})
#app.route("/webapp/login", methods = ["POST"])
def login():
user = request.get_json(force=True)
Email = user.get("email", "")
Password = user.get("password", "")
login = Login.login(Email, Password)
if login["Success"]:
session["email"] = Email
return login
#app.route("/webapp/checksession", methods = ["GET"])
def checksession():
sessionEmail = session.get("email", "")
if sessionEmail == "":
return utils.returnResult(False, "Session not valid")
return utils.returnResult(True, "")
And in the React app I use axios to do the login and check the session in the server, for example:
axios.get(APIURL + CHECK_SESSION, {withCredentials: true})
.then(response => {
console.log(response.headers);
setSession(response.data.success)
setCheckedSession(true)
})
.catch(err => {
setSession(false)
setCheckedSession(true)
if(err.response) {
}
else {
window.alert('Could not establish a connection to the server!');
}
});
In the dev tools we can see that the server is sending the cookie session:
But when I check the cookies for the app there's nothing there:
(Sorry for the Portuguese)
And in the axios promise handler, when I print the headers of the response, this is all I get:
So every time the react app checks if the user has a valid session in the server, the server creates a new session, which means that the react app is not saving and sending the cookie to the server.
Also, when I test this with postman everything works fine.
I searched all over the places and I can't find an answer for this. Can anyone help me figure out what I'm doing wrong, please?
Turns out it was missing configurations in the flask session:
app.config["SESSION_COOKIE_SAMESITE"] = "None"
app.config["SESSION_COOKIE_SECURE"] = True

How to access drf api from react after userd logged in in django

I have mostly been using Django templates for my front end and everything works fine. I want to learn about DRF and React and I want to be able to have both communicate to each other. I have react running on port 3000 and django on 8000 so there is a miscommunication and I can't test my code as I get the error 403 (forbidden). I have the following view:
#api_view(['GET'])
#authentication_classes([SessionAuthentication, BasicAuthentication])
#permission_classes([IsAuthenticated])
def user_details_api(request, *args, **kwargs):
current_user = request.user
id = current_user.id
status = 200
try:
obj = CustomUser.objects.get(id=id)
data = userSerializer(obj)
return Response(data.data, status=status)
except:
status = 404
return Response(status=404)
I have the following react end point:
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
let csrftoken = getCookie('csrftoken');
console.log("This is the token: "+csrftoken)
function loadUserInfo(callback){
let xhr = new XMLHttpRequest();
let method = 'GET';
let url = "http://127.0.0.1:8000/api/userdetails/6";
xhr.responseType = "json"; // Let the xhr request know that its getting a json
xhr.open(method, url); //This opens the request with the method and url entered
xhr.setRequestHeader("Content-Type","application/json")
if (csrftoken){
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
xhr.onload = function(){
if(xhr.status==403){
let detail = xhr.response.detail;
if(detail ==="Authentication credentials were not provided.");
if(window.location.href.indexOf("login")===-1){
window.location.href="/login"
}
}
callback(xhr.response, xhr.status)
}
xhr.onerror = function(){
callback({"message":"The request was an error"}, 400)
}
xhr.send();//Trigger that request
}
I see in the details that the credentials were not provided and I am wondering how to fix this as the tutorial I watched did not seem to provide any aside from logging in on the django side using the stock login form which I also did. I also noticed that the csrftoken is null. I also included CORS settings and trusted origins as well as drf settings:
ALLOWED_HOSTS = ['http://127.0.0.1','.cfe.sh','http://localhost','http://localhost:3000']
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOWED_ORIGINS = ['http://localhost:3000']
CSRF_TRUSTED_ORIGINS = ['http://localhost:3000','http://localhost:8000']
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
]
}
I am not sure how to do proceed, most solutions online deal with tokens and I am not sure that is the only solution specially since I am not entirely using react for the front end and the login page is rendered by Django. Any idea how to proceed in my use case would be appreciated as I only need to run some specific pages with react that will serve more as practice for me than anything else where I will delete and update the data. I am just starting to learn about this concept but cannot test code when my endpoints are not communicating.

Correct Flow for Google OAuth2 with PKCE through Client App to SAAS API Server

So we are working on a client application in Windows WPF. We want to include Google as a login option and intend to go straight to the current most secure method. At the moment we have spawned a web browser with the following methods to obtain a Authorization Code
private async void HandleGoogleLogin() {
State.Token = null;
var scopes = new string[] { "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/userinfo.profile", "openid" };
var request = GoogleOAuthRequest.BuildLoopbackRequest(scopes);
var listener = new HttpListener();
listener.Prefixes.Add(request.RedirectUri);
listener.Start();
// note: add a reference to System.Windows.Presentation and a 'using System.Windows.Threading' for this to compile
await Dispatcher.Invoke(async () => {
googleLoginBrowser.Address = request.AuthorizationRequestUri;
});
// here, we'll wait for redirection from our hosted webbrowser
var context = await listener.GetContextAsync();
// browser has navigated to our small http servern answer anything here
string html = string.Format("<html><body></body></html>");
var buffer = Encoding.UTF8.GetBytes(html);
context.Response.ContentLength64 = buffer.Length;
var stream = context.Response.OutputStream;
var responseTask = stream.WriteAsync(buffer, 0, buffer.Length).ContinueWith((task) =>
{
stream.Close();
listener.Stop();
});
string error = context.Request.QueryString["error"];
if (error != null)
return;
string state = context.Request.QueryString["state"];
if (state != request.State)
return;
string code = context.Request.QueryString["code"];
await APIController.GoogleLogin(request, code, (success, resultObject) => {
if (!success) {
//Handle all request errors (username already exists, email already exists, etc)
} else {
((App)Application.Current).UserSettings.Email = resultObject["email"].ToString();
((App)Application.Current).SaveSettings();
}
attemptingLogin = false;
});
}
and
public static GoogleOAuthRequest BuildLoopbackRequest(params string[] scopes) {
var request = new GoogleOAuthRequest {
CodeVerifier = RandomDataBase64Url(32),
Scopes = scopes
};
string codeChallenge = Base64UrlEncodeNoPadding(Sha256(request.CodeVerifier));
const string codeChallengeMethod = "S256";
string scope = BuildScopes(scopes);
request.RedirectUri = string.Format("http://{0}:{1}/", IPAddress.Loopback, GetRandomUnusedPort());
request.State = RandomDataBase64Url(32);
request.AuthorizationRequestUri = string.Format("{0}?response_type=code&scope=openid%20profile{6}&redirect_uri={1}&client_id={2}&state={3}&code_challenge={4}&code_challenge_method={5}",
AuthorizationEndpoint,
Uri.EscapeDataString(request.RedirectUri),
ClientId,
request.State,
codeChallenge,
codeChallengeMethod,
scope);
return request;
}
To my understanding, from this point the client app has completed the required portion to have the user login to their google account and approve any additional privileges.
Our API/App server is in GoLang.
APIController.GoogleLogin
from above sends the CodeVerifier and AuthorizationCode to the GoLang application server to then finish off the OAuth2 Flow.
Is this the correct flow given our client-server setup?
If so, what is the best practice for the Go Server to retrieve a Access Token/Refresh Token and get user information? Should the client app be performing a looping check-in to the app server as the app server will not immediately have the required information to login?
Thanks for the help!

Azure B2C - 401 unauthorised trying to read id_token in code after logging in

I am trying to use the token granted by a secured AAD domain when using my web app
I followed the advice on this link: Retrieve Access Token within a AAD secured Azure Web App
I have managed to get as far as logging in and verifying the ./me URL correctly shows me my token
However when I try and call same token in code I get 401 unauthorised
I have been using the Resource Explorer to configure the additionalLoginParams and have tried to put the app ID as well as the graph URL but nothing has solved the problem
async public Task<string> GetToken()
{
HttpClient _client = new HttpClient();
string _token = "";
HttpResponseMessage response = await _client.GetAsync("https://alfreton.azurewebsites.net/.auth/me");
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
ReadUserToken readUserToken = new ReadUserToken();
readUserToken = JsonConvert.DeserializeObject<ReadUserToken>(responseBody);
_token = readUserToken.id_token;
return _token;
}
}
}
EDIT Following the advice below the code now looks like this but I am still getting an Unauthorized error messsage
async public Task<string> GetToken()
{
HttpClient _client = new HttpClient();
string _token = "";
string accessToken = this.Request.Headers["X-MS-TOKEN-AAD-ACCESS-TOKEN"];
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
HttpResponseMessage response = await _client.GetAsync("https://alfreton.azurewebsites.net/.auth/me");
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
ReadUserToken readUserToken = new ReadUserToken();
readUserToken = JsonConvert.DeserializeObject<ReadUserToken>(responseBody);
_token = readUserToken.id_token;
return _token;
}
When I read through the headers, I find there is X-MS-TOKEN-AAD-ID-TOKEN - can I use that to get an access token?
I agree with #juunas, the URL expects the authentication cookie to be passed in the request when you aceess ./me URL.
The provider-specific tokens are injected into the request header, so you can easily access them. Your provider is AAD, so it should be
string accessToken = this.Request.Headers["X-MS-TOKEN-AAD-ACCESS-TOKEN"];
OK I figured it out, what I needed to do is get X-MS-TOKEN-AAD-ID-TOKEN from the Request Headers after logging in then pass that in as the Bearer and that in turn got me a X-MS-TOKEN-AAD-ACCESS-TOKEN which I can use for accessing the API
Thanks loads!

SignalR authentication failed when passing "Bearer" through query string

I'd like to enable authentication in SignalR while the server was hosted in ASP.NET WebAPI which I'm using OAuth Bearer authrntication and the client is AngularJS.
On client side I originally pass the Bearer token through HTTP header and it works well with the WebAPI. But since SignalR JavsScript doesn't support adding HTTP headers in connection (it's because WebSocket doesn't support specifying HTTP headers) I need to pass the Bearer token through query string by using the code like self.connection.qs = { Bearer: 'xxxxxx' };
The problem is on the WebAPI side my SignalR always returned 401 Unauthorized.
Below is what I did on the WebAPI side.
1, I specified OAuthBearerAuthenticationOptions.Provider to QueryStringEnabledOAuthBearerAuthenticationProvider, which is a class I created inherited from OAuthBearerAuthenticationProvider that can retrieve Bearer token from query string. Code as below.
public class QueryStringEnabledOAuthBearerAuthenticationProvider : OAuthBearerAuthenticationProvider
{
private readonly string _name;
public QueryStringEnabledOAuthBearerAuthenticationProvider()
: this(OAuthDefaults.AuthenticationType)
{
}
public QueryStringEnabledOAuthBearerAuthenticationProvider(string name)
{
_name = name;
}
public override Task RequestToken(OAuthRequestTokenContext context)
{
// try to read token from base class (header) if possible
base.RequestToken(context).Wait();
if (string.IsNullOrWhiteSpace(context.Token))
{
// try to read token from query string
var token = context.Request.Query.Get(_name);
if (!string.IsNullOrWhiteSpace(token))
{
context.Token = token;
}
}
return Task.FromResult(null);
}
}
And registered it as below while WebAPI was started.
var options = new OAuthBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AuthenticationType = AuthenticationType,
Provider = new QueryStringEnabledOAuthBearerAuthenticationProvider(),
AccessTokenFormat = _accessTokenFormat,
};
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
app.UseOAuthBearerAuthentication(options);
2, In SignalR part I created an authorize attribute as below. Nothing changed just to be used to add break point.
public class BearerAuthorizeAttribute : AuthorizeAttribute
{
public override bool AuthorizeHubConnection(HubDescriptor hubDescriptor, IRequest request)
{
return base.AuthorizeHubConnection(hubDescriptor, request);
}
public override bool AuthorizeHubMethodInvocation(IHubIncomingInvokerContext hubIncomingInvokerContext, bool appliesToMethod)
{
return base.AuthorizeHubMethodInvocation(hubIncomingInvokerContext, appliesToMethod);
}
}
And registered it when WebAPI started as well.
app.Map("/signalr", map =>
{
// Setup the CORS middleware to run before SignalR.
// By default this will allow all origins. You can
// configure the set of origins and/or http verbs by
// providing a cors options with a different policy.
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration
{
// You can enable JSONP by uncommenting line below.
// JSONP requests are insecure but some older browsers (and some
// versions of IE) require JSONP to work cross domain
// EnableJSONP = true
EnableJavaScriptProxies = false
};
// Run the SignalR pipeline. We're not using MapSignalR
// since this branch already runs under the "/signalr"
// path.
map.RunSignalR(hubConfiguration);
// Require authentication for all hubs
var authorizer = new BearerAuthorizeAttribute();
var module = new AuthorizeModule(authorizer, authorizer);
GlobalHost.HubPipeline.AddModule(module);
});
I found, when SignalR connected my QueryStringEnabledOAuthBearerAuthenticationProvider.RequestToken was invoked and it retrieved Bearer token successfully. But then when SignalR BearerAuthorizeAttribute.AuthorizeHubConnection was invoked the parameter request.User still not authenticated. So it returned 401.
Can anyone give me some ideas on what's wrong I did, thanks.
I'm using headers, this is how I solved it
var authData = localStorageService.get('authorizationData');
var token = authData.token;
$.signalR.ajaxDefaults.headers = { Authorization: "Bearer " + token };
Hope it helps
I resolved this problem by unprotect the Bearer token from query string in my AuthorizeAttribute, and set the user principal into a new ServerRequest. For detailed information please check http://blog.shaunxu.me/archive/2014/05/27/set-context-user-principal-for-customized-authentication-in-signalr.aspx
This might not be the best solution but it worked.

Resources