Coder Social home page Coder Social logo

city-of-helsinki / tunnistamo Goto Github PK

View Code? Open in Web Editor NEW
7.0 28.0 23.0 1.71 MB

City of Helsinki single sign-on service

License: MIT License

Python 97.06% HTML 1.04% Dockerfile 0.43% Shell 0.65% SCSS 0.82%
python django-rest-framework single-sign-on oauth2 openid-connect jwt

tunnistamo's Introduction

Build status codecov Requirements

Tunnistamo

Set up with Docker

  1. Create a docker-compose.env.yaml file in the project folder:

    • you can use docker-compose.env.yaml.template as a base, it does not need any changes if you want all features enables
    • change DEBUG and the rest of the Django settings if needed
    • set entrypoint/startup variables according to taste
      • SETUP_DEV_OIDC, creates a working OIDC environment
      • CREATE_SUPERUSER, creates a superuser with credentials admin:admin ([email protected])
      • APPLY_MIGRATIONS, applies migrations on startup
      • GENERATE_OPENID_KEY, generates a RSA key on startup
  2. Run docker-compose up

The project is now running at localhost:8000

Set up w/o Docker

Prerequisites

Tunnistamo runs on postresql. Install the server on Debian based systems with:

apt install postgresql

Then create a postgres user and db as root:

createuser <your username>
createdb -O <your username> tunnistamo

Installing

Clone the repo:

git clone https://github.com/City-of-Helsinki/tunnistamo.git
cd tunnistamo

Initiate a virtualenv and install the Python requirements:

pyenv virtualenv 3.9.10 tunnistamo-env
pyenv local tunnistamo-env
pip install -r requirements.txt

You may choose some other Python version to install but currently Tunnistamo requires Python 3.

Create local_settings.py in the repo base dir containing the following line:

DEBUG = True

In case you want to modify the default database configurations, you may also modify them in the same file by adding these lines:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'custom_database',
        'USER': 'custom_user',
        'PASSWORD': 'your_password',
        'HOST': '127.0.0.1',
    }
}

Run migrations:

python manage.py migrate

Create admin user:

python manage.py createsuperuser

Create RSA keys:

python manage.py manage_openid_keys

In order to automatically rotate the server RSA key at set intervals the above command should be added to cron.daily.

Run dev server:

python manage.py runserver

and login to http://127.0.0.1:8000/ using the admin user credentials.

To access the themed views you also need to install npm and run npm install at the project root.

Developing

Outdated Python dependencies

Tunnistamo uses pip-tools to manage the Python dependencies.

Update the requirements with:

pip install -r requirements-dev.txt
pip-compile --upgrade requirements.in
pip-compile --upgrade requirements-dev.in
pip-compile --upgrade requirements-prod.in

Configuring

Client IP obtaining

Tunnistamo uses django-ipware to obtain client ip addresses for user login history entries. By default, a client ip address is read from REMOTE_ADDR. If you need to use some HTTP header(s) instead, for instance when deploying Tunnistamo behind a reverse proxy, use setting IPWARE_META_PRECEDENCE_ORDER to set the header(s), for example:

IPWARE_META_PRECEDENCE_ORDER = ('HTTP_X_FORWARDED_FOR',)

Getting geo location data for IP addresses

In order to get geo location data for IP addresses, which is in included user login history entries if available, you'll need GeoLite2 City dataset in binary format from here. Unzip it to somewhere (inside this repo /data/ is the preferred place as that is in .gitignore), and add setting GEOIP_PATH pointing to that directory.

See Django docs for more info.

Rotating server RSA keys with Key Manager

For added security the server RSA keys, used to sign/encrypt ID tokens, should be rotated at regular intervals. This can be done automatically with the Django admin utility manage_openid_keys provided in the Key Manager module. This utility performs the following tasks:

  1. If there are no server RSA keys one is created with KEY_MANAGER_RSA_KEY_LENGTH bits (default 4096).
  2. If an RSA key is older than KEY_MANAGER_RSA_KEY_MAX_AGE days the key is expired and a new one is created.
    • This happens also for all existing keys not recognized by the Key Manager
  3. If an RSA key has been expired over KEY_MANAGER_RSA_KEY_EXPIRATION_PERIOD days ago it is removed from the system.

This command should be run on production servers at regular intervals, e.g. once a day, using cron or similar tool.

See OIDC_provider docs for more information about server RSA keys.

Configuring Suomi.fi access levels

Suomi.fi authentication provider has dynamic scopes and claims based on access levels and attributes configured in a YAML file. The default YAML file, suomifi_fields.yaml, has configurations for suppea, keskilaaja and laaja access levels. The resulting OIDC scopes will be suomifi_suppea, suomifi_keskilaaja and suomifi_laaja, respectively. The claims these scopes provide are maps with the friendlyName of the Suomi.fi attribute as key and the value of that attribute as value.

The YAML file can be processed using command:

python manage.py populate_suomifi_attributes --load suomifi_fields.yaml

API documentation

When the dev server is running, auto-generated API documentation is available at http://localhost:8000/docs/

License

This project is licensed under the MIT License – see the LICENSE file for details.

tunnistamo's People

Contributors

ahukkanen avatar akikoskinen avatar antti-mikael avatar charn avatar dependabot[bot] avatar frwickst avatar hi-fi avatar hukka avatar igordavydsson avatar joonvena avatar juyrjola avatar mikkokeskinen avatar op-codento avatar op-lamminen avatar pkalliok avatar rikuoja avatar ruriky avatar snyk-bot avatar suutari-ai avatar terotik avatar terovirtanen avatar tituomin avatar tuomas777 avatar vikoivun avatar voneiden avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tunnistamo's Issues

tunnistamo Django admin log in fails using SOCIAL_AUTH_GITHUB_KEY, SOCIAL_AUTH_GITHUB_SECRET and ALLOW_CROSS_SITE_SESSION_COOKIE=True

Steps how to reproduce issue:

  • Add line 127.0.0.1 tunnistamo-backend into your hosts file and make sure the change takes effect (Possibly reboot to make extra sure)
    • /etc/hosts on Mac OS X and Linux
    • /Windows/System32/drivers/etc/hosts on Windows 10
  • git clone https://github.com/City-of-Helsinki/tunnistamo.git testing-tunnistamo
  • cd testing-tunnistamo
  • git checkout dbb0795e7f7e2bae5d9e93682c88e8e9ed9d35a1 (This is the most recent commit in develop branch on 2023-02-17)
  • cp docker-compose.env.yaml.template docker-compose.env.yaml
  • Open https://github.com/settings/developers/ in a web browser
    • Click "New OAuth App" button
    • Set "Application name" to local tunnistamo
    • Set "Homepage URL" to http://tunnistamo-backend:8000
    • Set "Application description" to Local tunnistamo for e.g. palvelutarjotin-admin
    • Set "Authorization callback URL" to http://tunnistamo-backend:8000/accounts/github/login/callback/
    • Click "Register application"
    • Open the created "local tunnistamo" OAuth App
    • Copy the client ID and put it into docker-compose.env.yaml as SOCIAL_AUTH_GITHUB_KEY=<client ID value>, e.g. SOCIAL_AUTH_GITHUB_KEY=2a78b94f1512dfbd4173
    • Click "Generate a new client secret"
    • Copy the client secret and put it into docker-compose.env.yaml as SOCIAL_AUTH_GITHUB_SECRET=<client secret value>, e.g. SOCIAL_AUTH_GITHUB_SECRET=e54f49ebd2e727af1da32f296e04671c9989364e
    • Add ALLOW_CROSS_SITE_SESSION_COOKIE=True into docker-compose.env.yaml (Tried without adding this and the bug didn't appear so this is involved!)
  • docker-compose up --build
  • Open Google Chrome in incognito mode to make sure it starts from a clean slate

Debugging

If you set tunnistamo/settings.py logging levels to DEBUG you can get more info:

diff
diff --git a/tunnistamo/settings.py b/tunnistamo/settings.py
index 113b2da..92ad3a9 100644
--- a/tunnistamo/settings.py
+++ b/tunnistamo/settings.py
@@ -336,22 +336,22 @@ LOGGING = {
     'loggers': {
         'django': {
             'handlers': ['console'],
-            'level': 'WARNING',
+            'level': 'DEBUG',
             'propagate': False,
         },
         'generic': {
             'handlers': ['console'],
-            'level': 'WARNING',
+            'level': 'DEBUG',
             'propagate': False,
         },
         'requests': {
             'handlers': ['console'],
-            'level': 'WARNING',
+            'level': 'DEBUG',
             'propagate': False,
         },
         'sorl.thumbnail': {
             'handlers': ['console'],
-            'level': 'WARNING',
+            'level': 'DEBUG',
             'propagate': False,
         },
         '': {

With the above logging level changes trying to log in to Django admin with admin/admin gives:

log
tunnistamo-backend | utils 2023-02-17 10:36:53,080 DEBUG (0.002) SELECT "users_user"."id", "users_user"."password", "users_user"."last_login", "users_user"."is_superuser", "users_user"."username", "users_user"."email", "users_user"."is_staff", "users_user"."is_active", "users_user"."date_joined", "users_user"."uuid", "users_user"."department_name", "users_user"."first_name", "users_user"."last_name", "users_user"."primary_sid", "users_user"."last_login_backend" FROM "users_user" WHERE "users_user"."username" = 'admin' LIMIT 21; args=('admin',)
tunnistamo-backend | utils 2023-02-17 10:36:53,208 DEBUG (0.002) SELECT (1) AS "a" FROM "django_session" WHERE "django_session"."session_key" = 'ty0o843p7qwsczsuzsotkleclvejp9er' LIMIT 1; args=('ty0o843p7qwsczsuzsotkleclvejp9er',)
tunnistamo-backend | utils 2023-02-17 10:36:53,210 DEBUG (0.001) INSERT INTO "django_session" ("session_key", "session_data", "expire_date") VALUES ('ty0o843p7qwsczsuzsotkleclvejp9er', 'e30:1pSy6n:24RUA6dlQXR7li9MJgjw_Rp5IClbSIeVIraiVr_w9Is', '2023-03-03T10:36:53.208660+00:00'::timestamptz); args=('ty0o843p7qwsczsuzsotkleclvejp9er', 'e30:1pSy6n:24RUA6dlQXR7li9MJgjw_Rp5IClbSIeVIraiVr_w9Is', datetime.datetime(2023, 3, 3, 10, 36, 53, 208660, tzinfo=<UTC>))
tunnistamo-backend | utils 2023-02-17 10:36:53,214 DEBUG (0.002) UPDATE "users_user" SET "last_login" = '2023-02-17T10:36:53.211632+00:00'::timestamptz WHERE "users_user"."id" = 1; args=(datetime.datetime(2023, 2, 17, 10, 36, 53, 211632, tzinfo=<UTC>), 1)
tunnistamo-backend | utils 2023-02-17 10:36:53,216 DEBUG (0.002) INSERT INTO "users_tunnistamosession" ("id", "data", "user_id", "created_at", "ended_at") VALUES ('31bfdbd5-193a-47b8-8d36-a612aaf48c2e'::uuid, NULL, 1, '2023-02-17T10:36:53.214428+00:00'::timestamptz, NULL); args=(UUID('31bfdbd5-193a-47b8-8d36-a612aaf48c2e'), None, 1, datetime.datetime(2023, 2, 17, 10, 36, 53, 214428, tzinfo=<UTC>), None)
tunnistamo-backend | utils 2023-02-17 10:36:53,218 DEBUG (0.001) UPDATE "users_tunnistamosession" SET "data" = '{"django_session_key": "ty0o843p7qwsczsuzsotkleclvejp9er"}', "user_id" = 1, "created_at" = '2023-02-17T10:36:53.214428+00:00'::timestamptz, "ended_at" = NULL WHERE "users_tunnistamosession"."id" = '31bfdbd5-193a-47b8-8d36-a612aaf48c2e'::uuid; args=('{"django_session_key": "ty0o843p7qwsczsuzsotkleclvejp9er"}', 1, datetime.datetime(2023, 2, 17, 10, 36, 53, 214428, tzinfo=<UTC>), UUID('31bfdbd5-193a-47b8-8d36-a612aaf48c2e'))
tunnistamo-backend | utils 2023-02-17 10:36:53,222 DEBUG (0.001) UPDATE "django_session" SET "session_data" = '.eJxVjssOgjAQRf-layH0QTu4dO83kJnOIPhoEwor478L0YUu7-vkPlWP6zL2a5G5n1gdlVaHX48w3iTtAV8xXXIdc1rmieq9Un_TUp8zy_307f4BRizjtm4huCDSgG8MDI7ZaorcsgnUduS08xB9Z8EBkdmUh4DC3uqmE0LwG3RZU5rKgo_cFyllyunzeCMNTNxWurNYuUBQAVtfodcGcXAQjajXG_wESsg:1pSy6n:esuRd63N3D0t0XbfQ0LZbTACWH1QmY182XcajB1nCNI', "expire_date" = '2023-03-03T10:36:53.221199+00:00'::timestamptz WHERE "django_session"."session_key" = 'ty0o843p7qwsczsuzsotkleclvejp9er'; args=('.eJxVjssOgjAQRf-layH0QTu4dO83kJnOIPhoEwor478L0YUu7-vkPlWP6zL2a5G5n1gdlVaHX48w3iTtAV8xXXIdc1rmieq9Un_TUp8zy_307f4BRizjtm4huCDSgG8MDI7ZaorcsgnUduS08xB9Z8EBkdmUh4DC3uqmE0LwG3RZU5rKgo_cFyllyunzeCMNTNxWurNYuUBQAVtfodcGcXAQjajXG_wESsg:1pSy6n:esuRd63N3D0t0XbfQ0LZbTACWH1QmY182XcajB1nCNI', datetime.datetime(2023, 3, 3, 10, 36, 53, 221199, tzinfo=<UTC>), 'ty0o843p7qwsczsuzsotkleclvejp9er')
tunnistamo-backend | basehttp 2023-02-17 10:36:53,223 INFO "POST /admin/login/ HTTP/1.1" 302 0
tunnistamo-backend | basehttp 2023-02-17 10:36:53,228 INFO "GET /admin/ HTTP/1.1" 302 0
tunnistamo-backend | base 2023-02-17 10:36:53,281 DEBUG Exception while resolving variable 'subtitle' in template 'admin/hel_login.html'.
tunnistamo-backend | Traceback (most recent call last):
tunnistamo-backend |   File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 829, in _resolve_lookup
tunnistamo-backend |     current = current[bit]
tunnistamo-backend |   File "/usr/local/lib/python3.9/site-packages/django/template/context.py", line 83, in __getitem__
tunnistamo-backend |     raise KeyError(key)
tunnistamo-backend | KeyError: 'subtitle'
tunnistamo-backend |
tunnistamo-backend | During handling of the above exception, another exception occurred:
tunnistamo-backend |
tunnistamo-backend | Traceback (most recent call last):
tunnistamo-backend |   File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 835, in _resolve_lookup
tunnistamo-backend |     if isinstance(current, BaseContext) and getattr(type(current), bit):
tunnistamo-backend | AttributeError: type object 'RequestContext' has no attribute 'subtitle'
tunnistamo-backend |
tunnistamo-backend | During handling of the above exception, another exception occurred:
tunnistamo-backend |
tunnistamo-backend | Traceback (most recent call last):
tunnistamo-backend |   File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 843, in _resolve_lookup
tunnistamo-backend |     current = current[int(bit)]
tunnistamo-backend | ValueError: invalid literal for int() with base 10: 'subtitle'
tunnistamo-backend |
tunnistamo-backend | During handling of the above exception, another exception occurred:
tunnistamo-backend |
tunnistamo-backend | Traceback (most recent call last):
tunnistamo-backend |   File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 848, in _resolve_lookup
tunnistamo-backend |     raise VariableDoesNotExist("Failed lookup for key "
tunnistamo-backend | django.template.base.VariableDoesNotExist: Failed lookup for key [subtitle] in [{'True': True, 'False': False, 'None': None}, {'csrf_token': <SimpleLazyObject: <function csrf.<locals>._get_val at 0x7fd9e8bb5550>>, 'request': <WSGIRequest: GET '/admin/login/?next=/admin/'>, 'user': <SimpleLazyObject: <django.contrib.auth.models.AnonymousUser object at 0x7fd9e95669d0>>, 'perms': <django.contrib.auth.context_processors.PermWrapper object at 0x7fd9e9578130>, 'messages': <django.contrib.messages.storage.fallback.FallbackStorage object at 0x7fd9e9566280>, 'DEFAULT_MESSAGE_LEVELS': {'DEBUG': 10, 'INFO': 20, 'SUCCESS': 25, 'WARNING': 30, 'ERROR': 40}, 'backends': <LazyDict: <function backends.<locals>.<lambda> at 0x7fd9e9ee2d30>>, 'REDIRECT_FIELD_NAME': 'next', 'REDIRECT_FIELD_VALUE': '/admin/', 'REDIRECT_QUERYSTRING': 'next=/admin/'}, {}, {'form': <AdminAuthenticationForm bound=False, valid=Unknown, fields=(username;password)>, 'view': <django.contrib.auth.views.LoginView object at 0x7fd9e97cfc40>, 'site_title': 'Django site admin', 'site_header': 'example.com admin', 'site_url': '/', 'has_permission': False, 'available_apps': [], 'is_popup': False, 'is_nav_sidebar_enabled': True, 'site_type': 'dev', 'redirect_path': '/admin/', 'helsinki_provider_installed': False, 'grappelli_installed': False, 'base_site_template': 'admin/base_site_default.html', 'title': 'Log in', 'app_path': '/admin/login/?next=/admin/', 'username': '', 'next': '/admin/', 'site': <Site: example.com>, 'site_name': 'example.com', 'LANGUAGE_CODE': 'en', 'LANGUAGE_BIDI': False}, {'block': <Block Node: title. Contents: [<IfNode>, <Variable Node: title>, <TextNode: ' | '>, <Variable Node: site_title|default:_('Django site admin')>]>}]
tunnistamo-backend | base 2023-02-17 10:36:53,286 DEBUG Exception while resolving variable 'subtitle' in template 'admin/hel_login.html'.
tunnistamo-backend | Traceback (most recent call last):
tunnistamo-backend |   File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 829, in _resolve_lookup
tunnistamo-backend |     current = current[bit]
tunnistamo-backend |   File "/usr/local/lib/python3.9/site-packages/django/template/context.py", line 83, in __getitem__
tunnistamo-backend |     raise KeyError(key)
tunnistamo-backend | KeyError: 'subtitle'
tunnistamo-backend |
tunnistamo-backend | During handling of the above exception, another exception occurred:
tunnistamo-backend |
tunnistamo-backend | Traceback (most recent call last):
tunnistamo-backend |   File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 835, in _resolve_lookup
tunnistamo-backend |     if isinstance(current, BaseContext) and getattr(type(current), bit):
tunnistamo-backend | AttributeError: type object 'RequestContext' has no attribute 'subtitle'
tunnistamo-backend |
tunnistamo-backend | During handling of the above exception, another exception occurred:
tunnistamo-backend |
tunnistamo-backend | Traceback (most recent call last):
tunnistamo-backend |   File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 843, in _resolve_lookup
tunnistamo-backend |     current = current[int(bit)]
tunnistamo-backend | ValueError: invalid literal for int() with base 10: 'subtitle'
tunnistamo-backend |
tunnistamo-backend | During handling of the above exception, another exception occurred:
tunnistamo-backend |
tunnistamo-backend | Traceback (most recent call last):
tunnistamo-backend |   File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 848, in _resolve_lookup
tunnistamo-backend |     raise VariableDoesNotExist("Failed lookup for key "
tunnistamo-backend | django.template.base.VariableDoesNotExist: Failed lookup for key [subtitle] in [{'True': True, 'False': False, 'None': None}, {'csrf_token': <SimpleLazyObject: <function csrf.<locals>._get_val at 0x7fd9e8bb5550>>, 'request': <WSGIRequest: GET '/admin/login/?next=/admin/'>, 'user': <SimpleLazyObject: <django.contrib.auth.models.AnonymousUser object at 0x7fd9e95669d0>>, 'perms': <django.contrib.auth.context_processors.PermWrapper object at 0x7fd9e9578130>, 'messages': <django.contrib.messages.storage.fallback.FallbackStorage object at 0x7fd9e9566280>, 'DEFAULT_MESSAGE_LEVELS': {'DEBUG': 10, 'INFO': 20, 'SUCCESS': 25, 'WARNING': 30, 'ERROR': 40}, 'backends': <LazyDict: <function backends.<locals>.<lambda> at 0x7fd9e9ee2d30>>, 'REDIRECT_FIELD_NAME': 'next', 'REDIRECT_FIELD_VALUE': '/admin/', 'REDIRECT_QUERYSTRING': 'next=/admin/'}, {}, {'form': <AdminAuthenticationForm bound=False, valid=Unknown, fields=(username;password)>, 'view': <django.contrib.auth.views.LoginView object at 0x7fd9e97cfc40>, 'site_title': 'Django site admin', 'site_header': 'example.com admin', 'site_url': '/', 'has_permission': False, 'available_apps': [], 'is_popup': False, 'is_nav_sidebar_enabled': True, 'site_type': 'dev', 'redirect_path': '/admin/', 'helsinki_provider_installed': False, 'grappelli_installed': False, 'base_site_template': 'admin/base_site_default.html', 'title': 'Log in', 'app_path': '/admin/login/?next=/admin/', 'username': '', 'next': '/admin/', 'site': <Site: example.com>, 'site_name': 'example.com', 'LANGUAGE_CODE': 'en', 'LANGUAGE_BIDI': False}, {'block': <Block Node: content_subtitle. Contents: [<IfNode>]>}]
tunnistamo-backend | basehttp 2023-02-17 10:36:53,298 INFO "GET /admin/login/?next=/admin/ HTTP/1.1" 200 2232
tunnistamo-backend | basehttp 2023-02-17 10:36:53,329 INFO "GET /sso/static/admin/css/base.css HTTP/1.1" 200 19513
tunnistamo-backend | basehttp 2023-02-17 10:36:53,335 INFO "GET /sso/static/admin/css/nav_sidebar.css HTTP/1.1" 200 2271
tunnistamo-backend | basehttp 2023-02-17 10:36:53,340 INFO "GET /sso/static/admin/css/login.css HTTP/1.1" 200 939
tunnistamo-backend | basehttp 2023-02-17 10:36:53,343 INFO "GET /sso/static/admin/css/fonts.css HTTP/1.1" 200 423
tunnistamo-backend | basehttp 2023-02-17 10:36:53,343 INFO "GET /sso/static/admin/js/nav_sidebar.js HTTP/1.1" 200 1360
tunnistamo-backend | basehttp 2023-02-17 10:36:53,347 INFO "GET /sso/static/admin/css/responsive.css HTTP/1.1" 200 18545
tunnistamo-backend | basehttp 2023-02-17 10:36:53,396 INFO "GET /sso/static/admin/fonts/Roboto-Regular-webfont.woff HTTP/1.1" 200 85876
tunnistamo-backend | basehttp 2023-02-17 10:36:53,403 INFO "GET /sso/static/admin/fonts/Roboto-Light-webfont.woff HTTP/1.1" 200 85692

The most pertinent section of the log seems to be:

tunnistamo-backend | base 2023-02-17 10:36:53,286 DEBUG Exception while resolving variable 'subtitle' in template 'admin/hel_login.html'.
tunnistamo-backend | Traceback (most recent call last):
tunnistamo-backend |   File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 829, in _resolve_lookup
tunnistamo-backend |     current = current[bit]
tunnistamo-backend |   File "/usr/local/lib/python3.9/site-packages/django/template/context.py", line 83, in __getitem__
tunnistamo-backend |     raise KeyError(key)
tunnistamo-backend | KeyError: 'subtitle'
tunnistamo-backend |
tunnistamo-backend | During handling of the above exception, another exception occurred:
tunnistamo-backend |
tunnistamo-backend | Traceback (most recent call last):
tunnistamo-backend |   File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 835, in _resolve_lookup
tunnistamo-backend |     if isinstance(current, BaseContext) and getattr(type(current), bit):
tunnistamo-backend | AttributeError: type object 'RequestContext' has no attribute 'subtitle'
tunnistamo-backend |
tunnistamo-backend | During handling of the above exception, another exception occurred:
tunnistamo-backend |
tunnistamo-backend | Traceback (most recent call last):
tunnistamo-backend |   File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 843, in _resolve_lookup
tunnistamo-backend |     current = current[int(bit)]
tunnistamo-backend | ValueError: invalid literal for int() with base 10: 'subtitle'
tunnistamo-backend |
tunnistamo-backend | During handling of the above exception, another exception occurred:
tunnistamo-backend |
tunnistamo-backend | Traceback (most recent call last):
tunnistamo-backend |   File "/usr/local/lib/python3.9/site-packages/django/template/base.py", line 848, in _resolve_lookup
tunnistamo-backend |     raise VariableDoesNotExist("Failed lookup for key "
tunnistamo-backend | django.template.base.VariableDoesNotExist: Failed lookup for key [subtitle] in [{'True': True, 'False': False, 'None': None}, {'csrf_token': <SimpleLazyObject: <function csrf.<locals>._get_val at 0x7fd9e8bb5550>>, 'request': <WSGIRequest: GET '/admin/login/?next=/admin/'>, 'user': <SimpleLazyObject: <django.contrib.auth.models.AnonymousUser object at 0x7fd9e95669d0>>, 'perms': <django.contrib.auth.context_processors.PermWrapper object at 0x7fd9e9578130>, 'messages': <django.contrib.messages.storage.fallback.FallbackStorage object at 0x7fd9e9566280>, 'DEFAULT_MESSAGE_LEVELS': {'DEBUG': 10, 'INFO': 20, 'SUCCESS': 25, 'WARNING': 30, 'ERROR': 40}, 'backends': <LazyDict: <function backends.<locals>.<lambda> at 0x7fd9e9ee2d30>>, 'REDIRECT_FIELD_NAME': 'next', 'REDIRECT_FIELD_VALUE': '/admin/', 'REDIRECT_QUERYSTRING': 'next=/admin/'}, {}, {'form': <AdminAuthenticationForm bound=False, valid=Unknown, fields=(username;password)>, 'view': <django.contrib.auth.views.LoginView object at 0x7fd9e97cfc40>, 'site_title': 'Django site admin', 'site_header': 'example.com admin', 'site_url': '/', 'has_permission': False, 'available_apps': [], 'is_popup': False, 'is_nav_sidebar_enabled': True, 'site_type': 'dev', 'redirect_path': '/admin/', 'helsinki_provider_installed': False, 'grappelli_installed': False, 'base_site_template': 'admin/base_site_default.html', 'title': 'Log in', 'app_path': '/admin/login/?next=/admin/', 'username': '', 'next': '/admin/', 'site': <Site: example.com>, 'site_name': 'example.com', 'LANGUAGE_CODE': 'en', 'LANGUAGE_BIDI': False}, {'block': <Block Node: content_subtitle. Contents: [<IfNode>]>}]
  • Googling with the error messages found Django issue #32681 https://code.djangoproject.com/ticket/32681 which has been fixed in https://code.djangoproject.com/changeset/4e5bbb6ef2287126badd32842b239f4a8a7394ca/
  • Checked that django 3.2.16 had at least the test_render_views_no_subtitle test from django's 4e5bbb6ef2287126badd32842b239f4a8a7394ca merged into it.
  • Checked that the django version inside the docker container is django 3.2.16 by
    • docker-compose exec django bash
      • python
        • import django
        • django.VERSION → gives (3, 2, 16, 'final', 0)
  • So it seems this problem should not be present in django 3.2.16 but it is (Didn't check exactly that whether all the changes were incorporated from the django issue #32681 into django 3.2.16 release and whether its test_render_views_no_subtitle test passes)

Screenshots

After trying to log in with admin/admin

image

Add line-ending rules to .gitattributes

Problem

Certain files are expected to be in LF line-endings during the Docker build process, but depending on a users' git config core.autocrlf setting, these files might not be converted correctly for Windows users.

Motivation

Tunnistamo Docker container cannot be run successfully on Windows-based platforms.

Solution

Two files that should be changed are ./docker-entrypoint.sh and ./manage.py.

If ./docker-entrypoint.sh is some other line-ending than LF, the following error will be given when the docker container tries to start:

exec ./docker-entrypoint.sh: no such file or directory

If ./manage.py is some other line-ending than LF, the following error will be given:

Applying database migrations...
/usr/bin/env: ‘python\r’: No such file or directory

The following additions to ./.gitattributes should be made to fix the issues:

manage.py text eol=lf
*.sh text eol=lf

Additionally, the command git add --renormalize . should be run to convert the line endings according to these rules.

Get rid of username for social media logins

Currently User.username is automatically generated for social media logins. Usernames are not unique, so it's better to stop using them as semantic entities altogether. Fill usernames with UUIDs.

Might need fiddling with django-helusers.

OIDC scopes related tests fail because of mismatch between "Sähköposti" and "Sähköpostiosoite" texts

Steps how to reproduce issue:

  • git clone https://github.com/City-of-Helsinki/tunnistamo.git testing-tunnistamo
  • cd testing-tunnistamo
  • git checkout dbb0795e7f7e2bae5d9e93682c88e8e9ed9d35a1 (This is the most recent commit in develop branch on 2023-02-17)
  • cp docker-compose.env.yaml.template docker-compose.env.yaml
  • docker-compose up
  • docker-compose exec django bash
    • pytest . -vv
============================================================================================ short test summary info =============================================================================================
FAILED scopes/tests/test_api.py::test_get_oidc_scopes_list - AssertionError: assert {'fi': 'Sähköposti', 'en': 'Email', 'sv': 'E-postadress'} == {'fi': 'Sähköpostiosoite', 'sv': 'E-postadress', 'en': 'Email'}
FAILED users/tests/test_user_consent_api.py::test_get[True-list] - AssertionError: assert {'fi': 'Sähköposti', 'en': 'Email', 'sv': 'E-postadress'} == {'fi': 'Sähköpostiosoite', 'sv': 'E-postadress', 'en': 'Email'}
FAILED users/tests/test_user_consent_api.py::test_get[True-detail] - AssertionError: assert {'fi': 'Sähköposti', 'en': 'Email', 'sv': 'E-postadress'} == {'fi': 'Sähköpostiosoite', 'sv': 'E-postadress', 'en': 'Email'}
============================================================================ 3 failed, 489 passed, 1022 warnings in 184.80s (0:03:04) ============================================================================

Full log of the pytest . -vv:

Possible fix:

diff --git a/scopes/tests/test_api.py b/scopes/tests/test_api.py
index 58078fc..6dbf763 100644
--- a/scopes/tests/test_api.py
+++ b/scopes/tests/test_api.py
@@ -44,7 +44,7 @@ def test_get_oidc_scopes_list(api_client):
     assert [s['id'] for s in results] == EXPECTED_OIDC_SCOPES
     email_scope_data = next(s for s in results if s['id'] == 'email')
     assert email_scope_data.keys() == {'id', 'name', 'description'}
-    assert email_scope_data['name'] == {'fi': 'Sähköpostiosoite', 'sv': 'E-postadress', 'en': 'Email'}
+    assert email_scope_data['name'] == {'fi': 'Sähköposti', 'sv': 'E-postadress', 'en': 'Email'}
 
 
 def test_get_also_api_scopes_list(api_client):
diff --git a/users/tests/test_user_consent_api.py b/users/tests/test_user_consent_api.py
index e791e34..6c068fe 100644
--- a/users/tests/test_user_consent_api.py
+++ b/users/tests/test_user_consent_api.py
@@ -79,7 +79,7 @@ def test_get(user_api_client, endpoint, scope_included, service):
 
         assert oidc_scope.keys() == {'id', 'name', 'description'}
         assert oidc_scope['id'] == 'email'
-        assert oidc_scope['name'] == {'fi': 'Sähköpostiosoite', 'sv': 'E-postadress', 'en': 'Email'}
+        assert oidc_scope['name'] == {'fi': 'Sähköposti', 'sv': 'E-postadress', 'en': 'Email'}
         assert 'en' in oidc_scope['description']
 
         assert api_scope.keys() == {'id', 'name', 'description'}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.