Unable to set cookies using Falcon API and Python
Asked Answered
M

2

7

I'm trying to develop a user management interface for my project using the following:

  • Python 2.7
  • falcon 1.4.1
  • falcon-cors 1.1.7
  • gunicorn 19.9.0

I'm testing the login page in Google Chrome initiated by run command in Pycharm Professional.

Operating System: Ubuntu 18.04 LTS

import falcon
from falcon_cors import CORS
cors = CORS(allow_all_origins=True,allow_all_headers=True,allow_all_methods=True)

class User:
    def __init__(self):
        self.name = 'Users API'

    def on_post(self, req, resp):
        try:
            data = urlparse.parse_qs(req.stream.read())
            if "loginEmail" in data.keys() and "loginPassword" in data.keys():
                email = data['loginEmail'][0]
                password = data['loginPassword'][0]
                result = self.authenticate(email, password)
                if result["status"]=="Success":
                    resp.set_cookie('session', result["session"],path="/",domain="192.168.32.17:5000",secure=False)
            else:
                raise Exception, "Email or Password not provided"

            if len(result) <= 0:
                raise Exception, 'Empty Response'
            resp.body = json.dumps(result)

        except Exception as e:
            resp.body = json.dumps({'status': 'Error', 'message': e.message, 'details': str(e)})

    def on_get(self, req, resp):
        try:
            data = req.params
            cookies = req.cookies
            if "session" in cookies.keys():
                session = cookies['session']
                result=self.get(session,data)
                if len(result) <= 0:
                    raise Exception, 'Empty Response'
            else:
                raise Exception, "Session Terminated"

            resp.body = json.dumps(result)
        except Exception as e:
            resp.body = json.dumps({'status': 'Error','message': e.message,'details': str(e)})

api = falcon.API(middleware=[cors.middleware])
api.add_route('/user', User())

The basic webpage is as given below:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My Project</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body onload="refresh()">
<form method="post" action="http://192.168.32.17:5000/user" accept-charset="UTF-8" id="login-nav">
    <input type="email" name="loginEmail" placeholder="Email address" required>
    <input type="password" name="loginPassword" placeholder="Password" required>
    <button type="submit" id="btnLogin">Sign in</button>
 </form>
<script>
    $(document).ready(function() {
        $('#login-nav').submit(function(){
            $.post($(this).attr('action'), $(this).serialize(), function(json) {
                refresh()
            }, 'json');
            return false;
       });
    });

   function refresh(){
            $.get("http://192.168.32.17:5000/user",  { 'fields': [ "name", "dp" ] }, function(json) {
                if (json["status"]=="Error"){
                    alert(json["message"])
                }
               else {
                $('#dd-username').text(json["data"]["name"])
                $("#dd-photo").attr("src",json["data"]["dp"])
                }
            }, 'json');
    }

    function getCookie(cname) {
        var name = cname + "=";
        var decodedCookie = decodeURIComponent(document.cookie);
        var ca = decodedCookie.split(';');
        for(var i = 0; i <ca.length; i++) {
            var c = ca[i];
            while (c.charAt(0) == ' ') {
                c = c.substring(1);
            }
            if (c.indexOf(name) == 0) {
                return c.substring(name.length, c.length);
            }
        }
        return "";
    }

    function checkCookie() {
        var session = getCookie("session");
        if (session ==null || session==""){
            return false
        }
        else{
            return true
        }
</script>
</body>
</html>

On login request I'm getting required response as given below:

{"status": "Success", "message": "Session has been created successfully", "session": "F26F75C27942DE27"}

But on refresh(), I'm getting following response:

{"status": "Error", "message": "Session Terminated"}

I also tried checking for cookie using chechCookie() method above and it returns false as well.

I also tried to check for cookies using "Right Click> Inspect Element > Network" and "Right Click> Inspect Element > EditThisCookie" but found it nowhere.

Then I tried setting the cookie in the browser using javascript by modifying the script above as given below:

 $('#login-nav').submit(function(){
    $.post($(this).attr('action'), $(this).serialize(), function(json) {
        setCookie("session",json["session"])
        refresh()
    }, 'json');
    return false;
  });

function setCookie(cname, cvalue, exdays) {
    var d = new Date();
    d.setTime(d.getTime() + (exdays*24*60*60*1000));
    var expires = "expires="+ d.toUTCString();
    document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}

Using this method, I was able to set cookies in the browser. checkCookie() returned True. I was also able to locate the session cookie in EditThisCookie plugin of Google Chrome.

BUT

When refresh() was called, it returned the same response Session Terminated. This means session was not found in req.cookies on server end.

I have also got re-opened the issue on GitHub as well. https://github.com/falconry/falcon/issues/947#issuecomment-422652126

enter image description here

enter image description here

Mariko answered 14/9, 2018 at 4:18 Comment(11)
At first you should use your browsers debugger to see if the Cookie header is properly set in the response.Puseyism
How would I do that? My setup: gunicorn to run server-side application a simple HTML form sending a post request to my API route in chrome I check cookies using this EditThisCookie plugin in chrome or by inspect feature.Mariko
I get response body perfectly but can't find the cookie anywhere. Even check in document.cookies using javascript.Mariko
Google: <name of your browser> debuggerPuseyism
I have added a screen shotMariko
I know Cookie is not being set and that's my problem. Falcon gives a simple method resp.set_cookie that should work. I'm unable to understand what could go wrong with that?Mariko
Unluckily going with you through the whole debugging process step by step is not a service we can offer on SO. You will have to use a debugger or print statements to find out what is going on on your own.Puseyism
I used chrome browser debugging and I checked using javascript. Cookie wasn't there. Using the Postman cookie is created. Looks like chrome is blocking cookies or there is some problem with ajax request.Mariko
You have to check the content of the HTTP response in the network tab if the header is set. And BTW: blackening the domain might protect your privacy but might also hide the problem why the cookies is not accepted.Puseyism
I notice you're including the port when using set_cookie. Afaik cookies are not port-specific, and I'm wondering if including this is causing it to fail.Munificent
Yep it crossed my mind so I tried setting domain without port as well. It still doesn't work.Mariko
G
0

You can try set cookie like to

def handler_app(environ, start_response):
    response_body = b'Works fine'
    status = '200 OK'

    response_headers = [
       ('Content-type', 'text/html'),
       ('Set-Cookie', 'theme=light'),
       ('Set-Cookie': 'sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT')
    ]

    start_response(status, response_headers)

    return [response_body]

from gunicorn documentation , hope this help you !!!

Goulet answered 25/9, 2018 at 22:55 Comment(0)
B
0

You can set the cookie in falcon like this...

class Resource(object):
    def on_get(self, req, resp):
        # Set the 'max-age' of the cookie to 10 minutes (600 seconds)
        # and the cookies domain to "example.com"
        resp.set_cookie("my_cookie", "my cookie value",
                        max_age=600, domain="example.com")

And get the cookie like this...

class Resource(object):
    def on_get(self, req, resp):

        cookies = req.cookies

        if "my_cookie" in cookies:
            my_cookie_value = cookies["my_cookie"]
        # ....

For more information read falcon docs --> https://falcon.readthedocs.io/en/0.3.0.1/api/cookies.html

Bianca answered 28/5, 2020 at 10:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.