SAML SSO - Error

Hello, try to configure the SAML SSO with Azur active directory.

I have this error !

FileNotFoundError: [Errno 2] No such file or directory: ‘/opt/seatable/seatable-server-latest/dtable-web/seahub/saml/attribute-maps’

Can oyu help me ?

Thanks

2023-02-27 13:33:56,974 [ERROR] django.request:230 log_response Internal Server Error: /saml2/metadata/
Traceback (most recent call last):
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/django/core/handlers/exception.py”, line 47, in inner
response = get_response(request)
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/django/core/handlers/base.py”, line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/django/views/generic/base.py”, line 70, in view
return self.dispatch(request, *args, **kwargs)
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/django/views/generic/base.py”, line 98, in dispatch
return handler(request, *args, **kwargs)
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/djangosaml2/views.py”, line 822, in get
conf = self.get_sp_config(request)
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/djangosaml2/views.py”, line 100, in get_sp_config
return get_config(self.get_config_loader_path(request), request)
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/djangosaml2/conf.py”, line 71, in get_config
return config_loader(request)
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/djangosaml2/conf.py”, line 48, in config_settings_loader
conf.load(copy.deepcopy(settings.SAML_CONFIG))
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/saml2/config.py”, line 338, in load
self.load_complex(cnf)
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/saml2/config.py”, line 266, in load_complex
acs = ac_factory(cnf.get(“attribute_map_dir”))
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/saml2/attribute_converter.py”, line 62, in ac_factory
for fil in sorted(os.listdir(path)):
FileNotFoundError: [Errno 2] No such file or directory: ‘/opt/seatable/seatable-server-latest/dtable-web/seahub/saml/attribute-maps’
2023-02-27 13:35:24,923 [ERROR] seahub.saml.views:52 _decorated SAML relevant settings invalid.
2023-02-27 13:35:24,923 [ERROR] seahub.saml.views:53 _decorated SAML_METADATA_LOCAL_FILE:
2023-02-27 13:35:24,923 [ERROR] seahub.saml.views:54 _decorated SAML_METADATA_REMOTE_URL:
2023-02-27 13:35:24,923 [ERROR] seahub.saml.views:55 _decorated SAML_PROVIDER_DOMAIN: azure.saml
2023-02-27 13:35:24,923 [ERROR] seahub.saml.views:56 _decorated SAML_ATTRIBUTE_MAP: {‘uid’: ‘uid’, ‘mail’: ‘contact_email’, ‘name’: ‘name’, ‘employeeid’: ‘employee_id’, ‘jobtitle’: ‘user_role’}
2023-02-27 13:35:24,923 [ERROR] seahub.saml.views:57 _decorated ENTITY_ID:

The information you provide is in no way sufficient to help you.

Most importantly, which version AND edition of SeaTable Server are you running? Also: Post your SAML configuration in dtable_web_settings.py! (Needless to say, you can remove credentials.)

More generally, please consult Read before you post in Admin Talk for good community practices.

You will fin below informations of my seaTable On-Premise installation

Operating system : Debian Linux 11

Informations système
Enterprise Edition Licence à vincent.dousset@symta.fr, expirera le 2025-01-18
Informations de version
3.3.7

-----  dtable_web_settings.py ----
$URL = "seatable-symta-fr"

IS_PRO_VERSION = True

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'HOST': 'db',
        'PORT': '3306',
        'USER': 'root',
        'PASSWORD': 'xxxxx',
        'NAME': 'dtable_db',
        'OPTIONS': {
            'charset': 'utf8mb4',
        },
    }
}

CACHES = {
    'default': {
        'BACKEND': 'django_pylibmc.memcached.PyLibMCCache',
        'LOCATION': 'memcached',
    },
    'locmem': {
        'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
    },
}
COMPRESS_CACHE_BACKEND = 'locmem'
SECRET_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'

# for dtable-server
DTABLE_PRIVATE_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
DTABLE_SERVER_URL = '$URL/dtable-server/'
DTABLE_SOCKET_URL = '$URL/'

# for dtable-web
DTABLE_WEB_SERVICE_URL = '$URL/'

# for dtable-db
DTABLE_DB_URL = '$URL/dtable-db/'

# for dtable-storage-server
DTABLE_STORAGE_SERVER_URL = 'http://127.0.0.1:6666/'
NEW_DTABLE_IN_STORAGE_SERVER = True

# for seaf-server
FILE_SERVER_ROOT = '$URL/seafhttp/'
ENABLE_USER_TO_SET_NUMBER_SEPARATOR = True
PLUGINS_REPO_ID='f59784a8-92b4-49b8-bb95-1b38e54b9ee0'


# onlyoffice
ENABLE_ONLYOFFICE = True
ONLYOFFICE_APIJS_URL = "https://SEATABLE_SERVER_HOSTNAME/onlyofficeds/web-apps/apps/api/documents/api.js"
ONLYOFFICE_FILE_EXTENSION = ('doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx', 'odt', 'fodt', 'odp', 'fodp', 'ods', 'fods', 'csv', 'ppsx', 'pps')
ONLYOFFICE_JWT_SECRET = 'secretjwttoken'

# saml sso
ENABLE_SAML = True
SAML_PROVIDER_DOMAIN = 'azure.saml'
# 'Key' is the user attribute of Azure SAML, 'value' is the user attribute of SeaTable. The uid attribute of SeaTable is required.
SAML_ATTRIBUTE_MAP = {
    'uid': 'uid',
    'mail': 'contact_email',
    'name': 'name',
    'employeeid': 'employee_id',   # Syncing user's employee ID from SAML
    'jobtitle': 'user_role',   # Syncing user's role from SAML
}
from os import path
import saml2
import saml2.saml
CERTS_DIR = '/opt/seatable/seatable-data/ssl/'
SP_SERVICE_URL = '$URL'
XMLSEC_BINARY = '/usr/bin/xmlsec1'   # full path to the xmlsec1 binary programm
ATTRIBUTE_MAP_DIR = '/opt/seatable/seatable-server-latest/dtable-web/seahub/saml/attribute-maps'
SAML_CONFIG = {
    'entityid': SP_SERVICE_URL + '/saml2/metadata/',   # your entity id
    'xmlsec_binary': XMLSEC_BINARY,
    'allow_unknown_attributes': True,
    'attribute_map_dir': ATTRIBUTE_MAP_DIR,
    # this block states what services we provide
    'service': {
        # we are just a lonely SP
        'sp': {
            'allow_unsolicited': True,
            'required_attributes': ['uid'],   # attributes that this SP need to identify a user
            'name': 'Federated SeaTable Service',
            'name_id_format': saml2.saml.NAMEID_FORMAT_EMAILADDRESS,
            'endpoints': {
                'assertion_consumer_service': [
                    (SP_SERVICE_URL + '/saml/acs/', saml2.BINDING_HTTP_POST),
                ],
            },
            'idp': {
                # App Federation Metadata URL
                'loginmicrosoftonlinecom/xxxxxxxx/federationmetadata/2007-06/federationmetadata.xml?appid=581b0eac-aa60-434b-86ea-c5d3219dc759': {
                    'single_sign_on_service': {
                        # SingleSignOnService
                        saml2.BINDING_HTTP_REDIRECT: 'loginmicrosoftonlinecom/xxxxxxx/saml2',
                    },
                    'single_logout_service': {
                        # SingleLogoutService
                        saml2.BINDING_HTTP_REDIRECT: 'loginmicrosoftonlinecom/xxxxxxxxxxx/saml2',
                    },
                },
            },
        },
    },
    'metadata': { 'local': [path.join(CERTS_DIR, 'SSO-Seatable.xml')], # where the idp metadata is stored
    },
    'debug': 1,   # set to 1 to output debugging information
    'cert_file': path.join(CERTS_DIR, 'idp.crt'),   # Signing from IdP
    'encryption_keypairs': [{
        'key_file': path.join(CERTS_DIR, 'wildcard_symta_fr.key'),   # private part
        'cert_file': path.join(CERTS_DIR, 'Wildcard_plus_CA_symta.crt'),   # public part
    }],
    'valid_for': 24*365,   # how long is our metadata valid
}

I replace https://seatable.symta.fr to seatable-symta-fr
and mircosoft url because i can’t post more than 2 link

Please proceed as follows:

  • Open the bash of the Docker container seatable: docker container exec -it seatable bash
  • Navigate to /opt/seatable/seatable-server-latest/dtable-web/seahub/saml: cd /opt/seatable/seatable-server-latest/dtable-web/seahub/saml
  • Create the folder attribute-maps: mkdir attribute-maps
  • Restart SeaTable Service: /opt/seatable/scripts/seatable.sh restart
  • Exit docker container: exit

Thanks for your post.

I apply the patch, now the error is different :

2023-02-28 07:39:14,093 [ERROR] seahub.saml.views:52 _decorated SAML relevant settings invalid.
2023-02-28 07:39:14,093 [ERROR] seahub.saml.views:53 _decorated SAML_METADATA_LOCAL_FILE:
2023-02-28 07:39:14,093 [ERROR] seahub.saml.views:54 _decorated SAML_METADATA_REMOTE_URL:
2023-02-28 07:39:14,093 [ERROR] seahub.saml.views:55 _decorated SAML_PROVIDER_DOMAIN: azure.saml
2023-02-28 07:39:14,093 [ERROR] seahub.saml.views:56 _decorated SAML_ATTRIBUTE_MAP: {‘uid’: ‘uid’, ‘mail’: ‘contact_email’, ‘name’: ‘name’, ‘employeeid’: ‘employee_id’, ‘jobtitle’: ‘user_role’}
2023-02-28 07:39:14,093 [ERROR] seahub.saml.views:57 _decorated ENTITY_ID:
2023-02-28 07:55:10,741 [ERROR] seahub.saml.views:52 _decorated SAML relevant settings invalid.
2023-02-28 07:55:10,742 [ERROR] seahub.saml.views:53 _decorated SAML_METADATA_LOCAL_FILE:
2023-02-28 07:55:10,742 [ERROR] seahub.saml.views:54 _decorated SAML_METADATA_REMOTE_URL:
2023-02-28 07:55:10,742 [ERROR] seahub.saml.views:55 _decorated SAML_PROVIDER_DOMAIN: azure.saml
2023-02-28 07:55:10,742 [ERROR] seahub.saml.views:56 _decorated SAML_ATTRIBUTE_MAP: {‘uid’: ‘uid’, ‘mail’: ‘contact_email’, ‘name’: ‘name’, ‘employeeid’: ‘employee_id’, ‘jobtitle’: ‘user_role’}
2023-02-28 07:55:10,742 [ERROR] seahub.saml.views:57 _decorated ENTITY_ID:
2023-02-28 07:57:16,140 [ERROR] django.request:230 log_response Internal Server Error: /saml2/metadata/
Traceback (most recent call last):
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/django/core/handlers/exception.py”, line 47, in inner
response = get_response(request)
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/django/core/handlers/base.py”, line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/django/views/generic/base.py”, line 70, in view
return self.dispatch(request, *args, **kwargs)
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/django/views/generic/base.py”, line 98, in dispatch
return handler(request, *args, **kwargs)
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/djangosaml2/views.py”, line 822, in get
conf = self.get_sp_config(request)
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/djangosaml2/views.py”, line 100, in get_sp_config
return get_config(self.get_config_loader_path(request), request)
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/djangosaml2/conf.py”, line 71, in get_config
return config_loader(request)
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/djangosaml2/conf.py”, line 48, in config_settings_loader
conf.load(copy.deepcopy(settings.SAML_CONFIG))
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/saml2/config.py”, line 338, in load
self.load_complex(cnf)
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/saml2/config.py”, line 268, in load_complex
raise ConfigurationError(“No attribute converters, something is wrong!!”)
saml2.config.ConfigurationError: No attribute converters, something is wrong!!

Here is my Azure SAML configuration

Thanks for your help

Ragards

Hey Vincent,
I am quite certain that the problem arises from the fact that the developers are very actively working on the SAML implementation. You use SeaTable 3.3.7, but the configuration is for SeaTable 3.4.8. To be fair: this is not your fault, and the manual did not tell you that.

Here is the chnge request for this part of the manual from Febr. 17th:

By the way: with SeaTable 3.5 or 4.0 the SAML implementation will be much easier. Then only some parameters will be needed.

Back to your issue: I see two possible solutions. Tomorrow we will publish SeaTable 3.4.8 to docker hub and then the manual should match with your version. Or you change the configuration back to your 3.3.7 version. This would mean:

  • Remove ATTRIBUTE_MAP_DIR
  • Remove SAML_CONFIG: { attribute_map_dir
  • Add SAML_METADATA_REMOTE_URL
  • Add SAML_PROVIDER_DOMAIN
  • Add SAML_ENTITY_ID

In either way: I will try to support you in implementing it.
Christoph

Thanks for this information.

I wait for the 3.4.8 version.

Regards

Is there a specific procedure to migrate 3.3.7 to 3.4.8 ?

is the Upgrade Manual - SeaTable Admin Manual should be ok ?

Of course. You can update your SeaTable Server as described in the manual.

My version is now 3.4.8

The error change :

FileNotFoundError: [Errno 2] No such file or directory: ‘/opt/seatable/seatable-data/ssl/idp.crt’

(error log complete at the bottom)

But the file exist :

seatable@seatable:~$ nano /opt/seatable/seatable-data/ssl/idp.crt
GNU nano 5.4 /opt/seatable/seatable-data/ssl/idp.crt
-----BEGIN CERTIFICATE-----
MIIC8DCCAdigAwIBAgIQGv14x4YEzb9GCZvPVLomzTANBgkqhkiG9w0BAQsFADA0MTIwMAYDVQQD***************************************************************************************************************
-----END CERTIFICATE-----


2023-03-01 08:27:47,381 [ERROR] django.request:224 log_response Internal Server Error: /saml2/metadata/
Traceback (most recent call last):
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/django/core/handlers/exception.py”, line 47, in inner
response = get_response(request)
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/django/core/handlers/base.py”, line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/django/views/generic/base.py”, line 70, in view
return self.dispatch(request, *args, **kwargs)
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/django/views/generic/base.py”, line 98, in dispatch
return handler(request, *args, **kwargs)
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/djangosaml2/views.py”, line 822, in get
conf = self.get_sp_config(request)
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/djangosaml2/views.py”, line 100, in get_sp_config
return get_config(self.get_config_loader_path(request), request)
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/djangosaml2/conf.py”, line 71, in get_config
return config_loader(request)
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/djangosaml2/conf.py”, line 48, in config_settings_loader
conf.load(copy.deepcopy(settings.SAML_CONFIG))
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/saml2/config.py”, line 338, in load
self.load_complex(cnf)
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/saml2/config.py”, line 272, in load_complex
self.setattr(“”, “metadata”, self.load_metadata(cnf[“metadata”]))
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/saml2/config.py”, line 385, in load_metadata
mds = MetadataStore(
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/saml2/mdstore.py”, line 1043, in init
self.security = security_context(config)
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/saml2/sigver.py”, line 1014, in security_context
return SecurityContext(
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/saml2/sigver.py”, line 1241, in init
self.my_cert = read_cert_from_file(cert_file, cert_type)
File “/opt/seatable/seatable-server-latest/dtable-web/thirdpart/saml2/cert.py”, line 352, in read_cert_from_file
with open(cert_file, “rb”) as fp:
FileNotFoundError: [Errno 2] No such file or directory: ‘/opt/seatable/seatable-data/ssl/idp.crt’

You must differentiate the paths for the docker host and the docker container.
It is true that the file exists: /opt/seatable/seatable-data/ssl/idp.crt at the DOCKER HOST but this is not what you have to configure in dtable_web_settings.py.

The certificate is not available at the DOCKER CONTAINER at this location. The path depends on your docker-compose file, but it will be quite probably “/shared/ssl”.

So in dtable_web_settings.py the CERTS_DIR has to be correct for the paths of docker container.

Thanks a lot for your help, it’s ok now !

Just another question, when i log with SSO, in the name in the user parameters, i don’t have the name but a suite of letter and number ?

Then your attribute mapping is not correct.

Install a browser plugin like SAML Chrome Panel and check the attribute names and the values.

Ok, great !

The attribute “name” missing in my configuration.

Is there a way to force the sso login, and bypass the login form ?

I find the way, with a shortcut to https://server_url/sso

Regards

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.