kimai / kimai

Kimai is a web-based multi-user time-tracking application. Works great for everyone: freelancers, companies, organizations - everyone can track their times, generate reports, create invoices and do so much more. SaaS version available at https://www.kimai.cloud
https://www.kimai.org
GNU Affero General Public License v3.0
3.01k stars 529 forks source link

Failing redirect #1049

Closed Stadly closed 4 years ago

Stadly commented 4 years ago

Our Kimai installation is available on a url like this: https://kimai.mysite.com. When I open that url, I am redirected to https://kimai.mysite.com/en/timesheet/. Some users, however, are redirected to https://timesheet/. I have gotten three reports of this behavior so far, and I installed the system two days ago. If they enter the the full url https://kimai.mysite.com/en/timesheet/, they are able to use Kimai.

I logged the redirects that happen, and they go like this:

  1. Request: https://kimai.mysite.com/
  2. Redirect: /en/homepage
  3. Redirect: //timesheet/

When I open the url, these are the redirects:

  1. Request: https://kimai.mysite.com/
  2. Redirect: /en/homepage
  3. Redirect: /en/timesheet/

Could it have something to do with the locale? The locale seems to be missing from the erroneous redirect, and as you can see from the more extensive logs below, Accept-Language does not start with en in the case where the redirect fails. I am not sure whether this is the case for everybody who has reported the problem.

More extensive logs of the redirects:

Erroneous redirects:

{
    "log": {
        "version": "1.2",
        "creator": {
            "name": "F12 Developer Tools",
            "version": ""
        },
        "entries": [
            {
                "startedDateTime": "2019-08-20T07:22:08.496Z",
                "time": 145,
                "request": {
                    "method": "GET",
                    "url": "https://kimai.mysite.com/",
                    "httpVersion": "HTTP/1.0",
                    "cookies": [
                        {
                            "name": "kimai_key",
                            "value": "0"
                        },
                        {
                            "name": "kimai_user",
                            "value": "0"
                        },
                        {
                            "name": "PHPSESSID",
                            "value": "..."
                        }
                    ],
                    "headers": [
                        {
                            "name": "Accept",
                            "value": "text/html, application/xhtml+xml, application/xml; q=0.9, */*; q=0.8"
                        },
                        {
                            "name": "Accept-Encoding",
                            "value": "gzip, deflate, br"
                        },
                        {
                            "name": "Accept-Language",
                            "value": "nn, en-GB; q=0.7, en; q=0.3"
                        },
                        {
                            "name": "Connection",
                            "value": "Keep-Alive"
                        },
                        {
                            "name": "Cookie",
                            "value": "..."
                        },
                        {
                            "name": "Host",
                            "value": "kimai.mysite.com"
                        },
                        {
                            "name": "Upgrade-Insecure-Requests",
                            "value": "1"
                        },
                        {
                            "name": "User-Agent",
                            "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18362"
                        }
                    ],
                    "queryString": [],
                    "headersSize": 647,
                    "bodySize": -1
                },
                "response": {
                    "status": 302,
                    "statusText": "Found",
                    "httpVersion": "HTTP/1.0",
                    "cookies": [],
                    "headers": [
                        {
                            "name": "Cache-Control",
                            "value": "max-age=0, must-revalidate, private"
                        },
                        {
                            "name": "Connection",
                            "value": "keep-alive"
                        },
                        {
                            "name": "Content-Length",
                            "value": "292"
                        },
                        {
                            "name": "Content-Type",
                            "value": "text/html; charset=UTF-8"
                        },
                        {
                            "name": "Date",
                            "value": "Tue, 20 Aug 2019 07:22:07 GMT"
                        },
                        {
                            "name": "Location",
                            "value": "/en/homepage"
                        },
                        {
                            "name": "Server",
                            "value": "Apache"
                        },
                        {
                            "name": "Vary",
                            "value": "User-Agent"
                        }
                    ],
                    "content": {
                        "size": 292,
                        "compression": -234,
                        "mimeType": "text/html",
                        "text": ""
                    },
                    "redirectURL": "",
                    "headersSize": 234,
                    "bodySize": 526
                },
                "cache": {},
                "timings": {
                    "blocked": 1,
                    "dns": 0,
                    "connect": 76,
                    "send": 0,
                    "wait": 68,
                    "receive": 0,
                    "ssl": 40
                }
            },
            {
                "startedDateTime": "2019-08-20T07:22:08.648Z",
                "time": 52,
                "request": {
                    "method": "GET",
                    "url": "https://kimai.mysite.com/en/homepage",
                    "httpVersion": "HTTP/1.0",
                    "cookies": [
                        {
                            "name": "kimai_key",
                            "value": "0"
                        },
                        {
                            "name": "kimai_user",
                            "value": "0"
                        },
                        {
                            "name": "PHPSESSID",
                            "value": "..."
                        }
                    ],
                    "headers": [
                        {
                            "name": "Accept",
                            "value": "text/html, application/xhtml+xml, application/xml; q=0.9, */*; q=0.8"
                        },
                        {
                            "name": "Accept-Encoding",
                            "value": "gzip, deflate, br"
                        },
                        {
                            "name": "Accept-Language",
                            "value": "nn, en-GB; q=0.7, en; q=0.3"
                        },
                        {
                            "name": "Connection",
                            "value": "Keep-Alive"
                        },
                        {
                            "name": "Cookie",
                            "value": "..."
                        },
                        {
                            "name": "Host",
                            "value": "kimai.mysite.com"
                        },
                        {
                            "name": "Upgrade-Insecure-Requests",
                            "value": "1"
                        },
                        {
                            "name": "User-Agent",
                            "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18362"
                        }
                    ],
                    "queryString": [],
                    "headersSize": 658,
                    "bodySize": -1
                },
                "response": {
                    "status": 302,
                    "statusText": "Found",
                    "httpVersion": "HTTP/1.0",
                    "cookies": [],
                    "headers": [
                        {
                            "name": "Cache-Control",
                            "value": "max-age=0, must-revalidate, private"
                        },
                        {
                            "name": "Connection",
                            "value": "keep-alive"
                        },
                        {
                            "name": "Content-Length",
                            "value": "292"
                        },
                        {
                            "name": "Content-Type",
                            "value": "text/html; charset=UTF-8"
                        },
                        {
                            "name": "Date",
                            "value": "Tue, 20 Aug 2019 07:22:07 GMT"
                        },
                        {
                            "name": "Location",
                            "value": "//timesheet/"
                        },
                        {
                            "name": "Server",
                            "value": "Apache"
                        },
                        {
                            "name": "Vary",
                            "value": "User-Agent"
                        }
                    ],
                    "content": {
                        "size": 292,
                        "compression": -234,
                        "mimeType": "text/html",
                        "text": ""
                    },
                    "redirectURL": "",
                    "headersSize": 234,
                    "bodySize": 526
                },
                "cache": {},
                "timings": {
                    "blocked": 1,
                    "dns": -1,
                    "connect": -1,
                    "send": 0,
                    "wait": 51,
                    "receive": 0,
                    "ssl": -1
                }
            }
        ]
    }
}

Working redirects:

{
    "log": {
        "version": "1.2",
        "creator": {
            "name": "F12 Developer Tools",
            "version": ""
        },
        "entries": [
            {
                "startedDateTime": "2019-08-20T08:07:31.896Z",
                "time": 52,
                "request": {
                    "method": "GET",
                    "url": "https://kimai.mysite.com/",
                    "httpVersion": "HTTP/1.0",
                    "cookies": [
                        {
                            "name": "PHPSESSID",
                            "value": "..."
                        }
                    ],
                    "headers": [
                        {
                            "name": "Accept",
                            "value": "text/html, application/xhtml+xml, application/xml; q=0.9, */*; q=0.8"
                        },
                        {
                            "name": "Accept-Encoding",
                            "value": "gzip, deflate, br"
                        },
                        {
                            "name": "Accept-Language",
                            "value": "en-US, nn; q=0.8, en-GB; q=0.6, en; q=0.4, nb; q=0.2"
                        },
                        {
                            "name": "Connection",
                            "value": "Keep-Alive"
                        },
                        {
                            "name": "Cookie",
                            "value": "..."
                        },
                        {
                            "name": "DNT",
                            "value": "1"
                        },
                        {
                            "name": "Host",
                            "value": "kimai.mysite.com"
                        },
                        {
                            "name": "Upgrade-Insecure-Requests",
                            "value": "1"
                        },
                        {
                            "name": "User-Agent",
                            "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763"
                        }
                    ],
                    "queryString": [],
                    "headersSize": 478,
                    "bodySize": -1
                },
                "response": {
                    "status": 302,
                    "statusText": "Found",
                    "httpVersion": "HTTP/1.0",
                    "cookies": [],
                    "headers": [
                        {
                            "name": "Cache-Control",
                            "value": "max-age=0, must-revalidate, private"
                        },
                        {
                            "name": "Connection",
                            "value": "keep-alive"
                        },
                        {
                            "name": "Content-Length",
                            "value": "292"
                        },
                        {
                            "name": "Content-Type",
                            "value": "text/html; charset=UTF-8"
                        },
                        {
                            "name": "Date",
                            "value": "Tue, 20 Aug 2019 08:07:31 GMT"
                        },
                        {
                            "name": "Location",
                            "value": "/en/homepage"
                        },
                        {
                            "name": "Server",
                            "value": "Apache"
                        },
                        {
                            "name": "Vary",
                            "value": "User-Agent"
                        }
                    ],
                    "content": {
                        "size": 292,
                        "compression": -234,
                        "mimeType": "text/html",
                        "text": ""
                    },
                    "redirectURL": "",
                    "headersSize": 234,
                    "bodySize": 526
                },
                "cache": {},
                "timings": {
                    "blocked": 0,
                    "dns": -1,
                    "connect": -1,
                    "send": 0,
                    "wait": 52,
                    "receive": 0,
                    "ssl": -1
                }
            },
            {
                "startedDateTime": "2019-08-20T08:07:31.955Z",
                "time": 47,
                "request": {
                    "method": "GET",
                    "url": "https://kimai.mysite.com/en/homepage",
                    "httpVersion": "HTTP/1.0",
                    "cookies": [
                        {
                            "name": "PHPSESSID",
                            "value": "..."
                        }
                    ],
                    "headers": [
                        {
                            "name": "Accept",
                            "value": "text/html, application/xhtml+xml, application/xml; q=0.9, */*; q=0.8"
                        },
                        {
                            "name": "Accept-Encoding",
                            "value": "gzip, deflate, br"
                        },
                        {
                            "name": "Accept-Language",
                            "value": "en-US, nn; q=0.8, en-GB; q=0.6, en; q=0.4, nb; q=0.2"
                        },
                        {
                            "name": "Connection",
                            "value": "Keep-Alive"
                        },
                        {
                            "name": "Cookie",
                            "value": "..."
                        },
                        {
                            "name": "DNT",
                            "value": "1"
                        },
                        {
                            "name": "Host",
                            "value": "kimai.mysite.com"
                        },
                        {
                            "name": "Upgrade-Insecure-Requests",
                            "value": "1"
                        },
                        {
                            "name": "User-Agent",
                            "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763"
                        }
                    ],
                    "queryString": [],
                    "headersSize": 489,
                    "bodySize": -1
                },
                "response": {
                    "status": 302,
                    "statusText": "Found",
                    "httpVersion": "HTTP/1.0",
                    "cookies": [],
                    "headers": [
                        {
                            "name": "Cache-Control",
                            "value": "max-age=0, must-revalidate, private"
                        },
                        {
                            "name": "Connection",
                            "value": "keep-alive"
                        },
                        {
                            "name": "Content-Length",
                            "value": "300"
                        },
                        {
                            "name": "Content-Type",
                            "value": "text/html; charset=UTF-8"
                        },
                        {
                            "name": "Date",
                            "value": "Tue, 20 Aug 2019 08:07:31 GMT"
                        },
                        {
                            "name": "Location",
                            "value": "/en/timesheet/"
                        },
                        {
                            "name": "Server",
                            "value": "Apache"
                        },
                        {
                            "name": "Vary",
                            "value": "User-Agent"
                        }
                    ],
                    "content": {
                        "size": 300,
                        "compression": -236,
                        "mimeType": "text/html",
                        "text": ""
                    },
                    "redirectURL": "",
                    "headersSize": 236,
                    "bodySize": 536
                },
                "cache": {},
                "timings": {
                    "blocked": 0,
                    "dns": -1,
                    "connect": -1,
                    "send": 0,
                    "wait": 47,
                    "receive": 0,
                    "ssl": -1
                }
            },
            {
                "startedDateTime": "2019-08-20T08:07:32.022Z",
                "time": 96,
                "request": {
                    "method": "GET",
                    "url": "https://kimai.mysite.com/en/timesheet/",
                    "httpVersion": "HTTP/1.0",
                    "cookies": [
                        {
                            "name": "PHPSESSID",
                            "value": "..."
                        }
                    ],
                    "headers": [
                        {
                            "name": "Accept",
                            "value": "text/html, application/xhtml+xml, application/xml; q=0.9, */*; q=0.8"
                        },
                        {
                            "name": "Accept-Encoding",
                            "value": "gzip, deflate, br"
                        },
                        {
                            "name": "Accept-Language",
                            "value": "en-US, nn; q=0.8, en-GB; q=0.6, en; q=0.4, nb; q=0.2"
                        },
                        {
                            "name": "Connection",
                            "value": "Keep-Alive"
                        },
                        {
                            "name": "Cookie",
                            "value": "..."
                        },
                        {
                            "name": "DNT",
                            "value": "1"
                        },
                        {
                            "name": "Host",
                            "value": "kimai.mysite.com"
                        },
                        {
                            "name": "Upgrade-Insecure-Requests",
                            "value": "1"
                        },
                        {
                            "name": "User-Agent",
                            "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763"
                        }
                    ],
                    "queryString": [],
                    "headersSize": 491,
                    "bodySize": -1
                },
                "response": {
                    "status": 200,
                    "statusText": "OK",
                    "httpVersion": "HTTP/1.0",
                    "cookies": [],
                    "headers": [
                        {
                            "name": "Cache-Control",
                            "value": "max-age=0, must-revalidate, private"
                        },
                        {
                            "name": "Connection",
                            "value": "keep-alive"
                        },
                        {
                            "name": "Content-Encoding",
                            "value": "gzip"
                        },
                        {
                            "name": "Content-Length",
                            "value": "8495"
                        },
                        {
                            "name": "Content-Type",
                            "value": "text/html; charset=UTF-8"
                        },
                        {
                            "name": "Date",
                            "value": "Tue, 20 Aug 2019 08:07:31 GMT"
                        },
                        {
                            "name": "Server",
                            "value": "Apache"
                        },
                        {
                            "name": "Vary",
                            "value": "Accept-Encoding,User-Agent"
                        }
                    ],
                    "content": {
                        "size": 8495,
                        "compression": -251,
                        "mimeType": "text/html",
                        "text": "..."
                    },
                    "redirectURL": "",
                    "headersSize": 251,
                    "bodySize": 8746
                },
                "cache": {},
                "timings": {
                    "blocked": 1,
                    "dns": -1,
                    "connect": -1,
                    "send": 0,
                    "wait": 94,
                    "receive": 1,
                    "ssl": -1
                }
            }
        ]
    }
}

Desktop/Smartphone Please complete the following information if this seems to be a frontend issue:

Additional context Add any other context about the problem here.

kevinpapst commented 4 years ago

I cannot think of any way that Kimai would create such a URL. In the theoretical case that a language is missing, an exception is thrown as there is no route existing within the app for //timesheet/ Can you reproduce it? The only way I see is if you use a new user, that did not set a language and that has no language in the URL (again, I don't see how that should be possible). Are you sure that your webserver is not intercepting some URLs?

Edit: I tried it with "Accept-Lanague: ab,en-US;q=0.5" and it still works.

Stadly commented 4 years ago

Managed to reproduce it!

Setting kimai2_user_preferences.language to NULL or the empty string for my user directly in the database causes a redirect to //timesheet/.

In our case, kimai2_user_preferences.language is the empty string for several users, after importing data from Kimai v1.

Setting kimai2_user_preferences.language to ab leads to a redirect to /ab/timesheet/, which yields a 500 server error.

It would probably be a good idea to sanitize the language, and not just blindly trust the database value.

kevinpapst commented 4 years ago

Hm, the error is in the importer then. I am not aware that you can manage to get invalid languages into the database otherwise. Thanks for that hint!

Can you try to replace the function within the file src/Controller/HomepageController.php:

    public function indexAction(Request $request): RedirectResponse
    {
        /** @var User $user */
        $user = $this->getUser();
        $userRoute = $user->getPreferenceValue('login.initial_view', InitialViewType::DEFAULT_VIEW);
        $userLanguage = $user->getLocale();
        $requestLanguage = $request->getLocale();

        $routes = [
            [$userRoute, $userLanguage],
            [$userRoute, $requestLanguage],
            [$userRoute, User::DEFAULT_LANGUAGE],
            [InitialViewType::DEFAULT_VIEW, $userLanguage],
            [InitialViewType::DEFAULT_VIEW, $requestLanguage],
        ];

        foreach ($routes as $routeSettings) {
            $route = $routeSettings[0];
            $language = $routeSettings[1];
            try {
                return $this->redirectToRoute($route, ['_locale' => $language]);
            } catch (\Exception $exception) {
                // something is wrong with the url parameters ...
            }
        }

        return $this->redirectToRoute(InitialViewType::DEFAULT_VIEW, ['_locale' => User::DEFAULT_LANGUAGE]);
    }

Afterwards run bin/console cache:clear --env=prod and bin/console cache:warmup --env=prod and see if the error still happens.

Stadly commented 4 years ago

When looking at the Kimai v1 database, there are several users with kimai_preferences.ui.lang set to the empty string. So it seems the importer have just copied the values from Kimai v1 to Kimai v2 without any validation or sanitization.

With the changes from your comment, I am redirected to /en/homepage and get a 500 error.

With the changes in #1054, I am redirected to /en/timesheet/, so that works :)

kevinpapst commented 4 years ago

Hooray & thanks for testing!

But I am not sure, that Kimai will work properly with an empty language. This might be fixed for future imports - but please update the preferences for your users, so that they don't have an empty language string.

lock[bot] commented 4 years ago

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. If you use Kimai on a daily basis, please consider donating to support further development of Kimai.