View Issue Details

IDProjectCategoryView StatusLast Update
0005966SOGoBackend Generalpublic2024-05-03 13:31
Reporterjpchev Assigned Toqhivert  
PrioritynormalSeverityminorReproducibilityalways
Status assignedResolutionopen 
Product Version5.10.0 
Summary0005966: infinite loop after SAML login with Keycloak
Description

Hi there,

I'm testing SOGo with SAML authentication, my ID provider is Keycloak 24.0.1.

I've managed to set up the integration, I'm correctly being redirected to Keycloak upon logging in, and I'm being redirected back to SOGo once logged in, but then SOGo sends me back again to the IDP, and so on in an infinite loop.

I don't see errors in SOGo logs.

This is the sequence of urls:

http://localhost:8081/SOGo

which redirects to

http://localhost:8088/realms/ase/protocol/saml?SAMLRequest=<...>&SigAlg=<...>&Signature=<...>

then I see a POST to

http://localhost:8081/SOGo/saml2-signon-post

which returns a successful SAMLResponse

and then a redirect to

http://localhost:8081/SOGo//myuser

which seems to log out the logged user: I see that this call unsets the cookie 0xHIGHFLYxSOGo
actually it is being set to "discard" and its validity is set to yesterday.

Can you please point me in the right direction?

I'm attaching my configuration (Dockerfile, sogo.conf and Apache site.conf) : I use SOGo with keycloak, postgresql and memcached in docker compose

Steps To Reproduce

run the command
docker-compose up
using the attached docker-compose.yml

Tagsdocker, saml, ubuntu

Activities

jpchev

jpchev

2024-05-03 08:22

reporter  

site.conf (3,224 bytes)   
<VirtualHost *:80>
    Alias /SOGo.woa/WebServerResources/ \
      /usr/lib/GNUstep/SOGo/WebServerResources/
    Alias /SOGo/WebServerResources/ \
        /usr/lib/GNUstep/SOGo/WebServerResources/

    <Directory /usr/lib/GNUstep/SOGo/>
        AllowOverride None

        <IfVersion < 2.4>      
            Order deny,allow
            Allow from all
        </IfVersion>
        <IfVersion >= 2.4>
            Require all granted
        </IfVersion>

        # Explicitly allow caching of static content to avoid browser specific behavior.
        # A resource's URL MUST change in order to have the client load the new version.
        <IfModule expires_module>
        ExpiresActive On
        ExpiresDefault "access plus 1 year"
        </IfModule>
    </Directory>

    ## Uncomment the following to enable proxy-side authentication, you will then
    ## need to set the "SOGoTrustProxyAuthentication" SOGo user default to YES and
    ## adjust the "x-webobjects-remote-user" proxy header in the "Proxy" section
    ## below.
    #
    ## For full proxy-side authentication:
    #<Location /SOGo>
    #  AuthType XXX
    #  Require valid-user
    #  SetEnv proxy-nokeepalive 1
    #  Allow from all
    #</Location>
    #
    ## For proxy-side authentication only for CardDAV and GroupDAV from external
    ## clients:
    #<Location /SOGo/dav>
    #  AuthType XXX
    #  Require valid-user
    #  SetEnv proxy-nokeepalive 1
    #  Allow from all
    #</Location>

    ProxyRequests Off
    SetEnv proxy-nokeepalive 1
    ProxyPreserveHost On

    # When using CAS, you should uncomment this and install cas-proxy-validate.py
    # in /usr/lib/cgi-bin to reduce server overloading
    #
    # ProxyPass /SOGo/casProxy http://localhost/cgi-bin/cas-proxy-validate.py
    # <Proxy http://localhost/app/cas-proxy-validate.py>
    #   Order deny,allow
    #   Allow from your-cas-host-addr
    # </Proxy>

    ProxyPass /SOGo http://127.0.0.1:20000/SOGo retry=0

    # Enable to use Microsoft ActiveSync support
    # Note that you MUST have many sogod workers to use ActiveSync.
    # See the SOGo Installation and Configuration guide for more details.
    #
    #ProxyPass /Microsoft-Server-ActiveSync \
    # http://127.0.0.1:20000/SOGo/Microsoft-Server-ActiveSync \
    # retry=60 connectiontimeout=5 timeout=360

    <Proxy http://127.0.0.1:20000/SOGo>
    ## adjust the following to your configuration
    RequestHeader set "x-webobjects-server-port" "8081"
    RequestHeader set "x-webobjects-server-name" "localhost"
    RequestHeader set "x-webobjects-server-url" "http://localhost:8081"

    ## When using proxy-side autentication, you need to uncomment and
    ## adjust the following line:
    RequestHeader unset "x-webobjects-remote-user"
    #  RequestHeader set "x-webobjects-remote-user" "%{REMOTE_USER}e" env=REMOTE_USER

    RequestHeader set "x-webobjects-server-protocol" "HTTP/1.0"

    AddDefaultCharset UTF-8

    Order allow,deny
    Allow from all
    </Proxy>

    # For Apple autoconfiguration
    <IfModule rewrite_module>
    RewriteEngine On
    RewriteRule ^/.well-known/caldav/?$ /SOGo/dav [R=301]
    RewriteRule ^/.well-known/carddav/?$ /SOGo/dav [R=301]
    </IfModule>

</VirtualHost>
site.conf (3,224 bytes)   
sogo.conf (6,091 bytes)   
{
  /* *********************  Main SOGo configuration file  **********************
   *                                                                           *
   * Since the content of this file is a dictionary in OpenStep plist format,  *
   * the curly braces enclosing the body of the configuration are mandatory.   *
   * See the Installation Guide for details on the format.                     *
   *                                                                           *
   * C and C++ style comments are supported.                                   *
   *                                                                           *
   * This example configuration contains only a subset of all available        *
   * configuration parameters. Please see the installation guide more details. *
   *                                                                           *
   * ~sogo/GNUstep/Defaults/.GNUstepDefaults has precedence over this file,    *
   * make sure to move it away to avoid unwanted parameter overrides.          *
   *                                                                           *
   * **************************************************************************/

  /* Database configuration (mysql:// or postgresql://) */
  SOGoProfileURL = "postgresql://sogo:sogo@ase-db:5432/sogo/sogo_user_profile";
  OCSFolderInfoURL = "postgresql://sogo:sogo@ase-db:5432/sogo/sogo_folder_info";
  OCSSessionsFolderURL = "postgresql://sogo:sogo@ase-db:5432/sogo/sogo_sessions_folder";

  /* Mail */
  //SOGoDraftsFolderName = Drafts;
  //SOGoSentFolderName = Sent;
  //SOGoTrashFolderName = Trash;
  SOGoIMAPServer = "imaps://imap.example.tld:143/?tls=yes";
  SOGoSieveServer = sieve://sieve.example.tld:4190;
  SOGoSMTPServer = smtp.example.tld;
  SOGoMailDomain = example.tld;
  SOGoMailingMechanism = smtp;
  SOGoForceExternalLoginWithEmail = YES;
  SOGoSMTPAuthenticationType = PLAIN;
  SOGoForceExternalLoginWithEmail = YES;
  //SOGoMailSpoolPath = /var/spool/sogo;
  //NGImap4ConnectionStringSeparator = "/";

  /* Notifications */
  //SOGoAppointmentSendEMailNotifications = NO;
  //SOGoACLsSendEMailNotifications = NO;
  //SOGoFoldersSendEMailNotifications = NO;

  /* Authentication */
  SOGoPasswordChangeEnabled = NO;

  /* SAML configuration */
  SOGoAuthenticationType = saml2;
  SOGoSAML2PrivateKeyLocation = "/etc/pki/tls/private/saml.key";
  SOGoSAML2CertificateLocation = "/etc/pki/tls/certs/saml.pem";
  SOGoSAML2IdpMetadataLocation = "/etc/sogo/idp-metadata.xml"; // this comes from http://localhost:8088/realms/ase/protocol/saml/descriptor
  SOGoSAML2IdpPublicKeyLocation = "/etc/pki/tls/certs/idp.pub";
  SOGoSAML2IdpCertificateLocation = "/etc/pki/tls/certs/idp.pem";
  SOGoSAML2LoginAttribute = "username";
  //SOGoSAML2LogoutEnabled = YES;
  //SOGoSAML2LogoutURL = "http://localhost/SOGo";

  /* LDAP authentication example */
  //SOGoUserSources = (
  //  {
  //    type = ldap;
  //    CNFieldName = cn;
  //    UIDFieldName = uid;
  //    IDFieldName = uid; // first field of the DN for direct binds
  //    bindFields = (uid, mail); // array of fields to use for indirect binds
  //    baseDN = "ou=users,dc=acme,dc=com";
  //    bindDN = "uid=sogo,ou=users,dc=acme,dc=com";
  //    bindPassword = qwerty;
  //    canAuthenticate = YES;
  //    displayName = "Shared Addresses";
  //    hostname = ldap://127.0.0.1:389;
  //    id = public;
  //    isAddressBook = YES;
  //  }
  //);

  /* LDAP AD/Samba4 example */
  //SOGoUserSources = (
  //  {
  //    type = ldap;
  //    CNFieldName = cn;
  //    UIDFieldName = sAMAccountName;
  //    baseDN = "CN=users,dc=domain,dc=tld";
  //    bindDN = "CN=sogo,CN=users,DC=domain,DC=tld";
  //    bindFields = (sAMAccountName, mail);
  //    bindPassword = password;
  //    canAuthenticate = YES;
  //    displayName = "Public";
  //    hostname = ldap://127.0.0.1:389;
  //    filter = "mail = '*'";
  //    id = directory;
  //    isAddressBook = YES;
  //  }
  //);


  /* SQL authentication example */
  /*  These database columns MUST be present in the view/table:
   *    c_uid - will be used for authentication -  it's the username or username@domain.tld)
   *    c_name - which can be identical to c_uid -  will be used to uniquely identify entries
   *    c_password - password of the user, plain-text, md5 or sha encoded for now
   *    c_cn - the user's common name - such as "John Doe"
   *    mail - the user's mail address
   *  See the installation guide for more details
   */
  //SOGoUserSources =
  //  (
  //    {
  //      type = sql;
  //      id = directory;
  //      viewURL = "postgresql://sogo:sogo@127.0.0.1:5432/sogo/sogo_view";
  //      canAuthenticate = YES;
  //      isAddressBook = YES;
  //      userPasswordAlgorithm = md5;
  //    }
  //  );

  /* Web Interface */
  //SOGoPageTitle = SOGo;
  //SOGoVacationEnabled = YES;
  //SOGoForwardEnabled = YES;
  //SOGoSieveScriptsEnabled = YES;
  //SOGoMailAuxiliaryUserAccountsEnabled = YES;
  //SOGoTrustProxyAuthentication = NO;
  //SOGoXSRFValidationEnabled = YES;

  /* General */
  //SOGoLanguage = English;
  //SOGoTimeZone = America/Montreal;
  //SOGoCalendarDefaultRoles = (
  //  PublicDAndTViewer,
  //  ConfidentialDAndTViewer
  //);
  //SOGoSuperUsernames = (sogo1, sogo2); // This is an array - keep the parens!
  //SxVMemLimit = 384;
  //WOPidFile = "/var/run/sogo/sogo.pid";


  // reach memcached through docker
  SOGoMemcachedHost = "ase-memcached";
  
  // this has a great impact on performance: you should adjust the number
  // of workers according to the number of users and the performance of your
  // machine
  WorkersCount = 4;
  


  
  /* Debug */
  SoDebugObjectTraversal = YES;
  GCSFolderDebugEnabled = YES;
  GCSFolderStoreDebugEnabled = YES;
  SoSecurityManagerDebugEnabled = YES;
  SOGoDebugRequests = YES;
  SoDebugBaseURL = YES;
  //ImapDebugEnabled = YES;
  //LDAPDebugEnabled = YES;
  PGDebugEnabled = YES;
  //MySQL4DebugEnabled = YES;
  SOGoUIxDebugEnabled = YES;
  WODontZipResponse = YES;
  WOLogFile = /var/log/sogo/sogo.log;
  WOWorkersCount = 10;
}
sogo.conf (6,091 bytes)   
docker-compose.yml (1,313 bytes)   
version: '3.7'

services:
  test-db:
    container_name: test-db
    image: docker.io/postgres
    restart: always
    ports:
      - 5432:5432
    environment:
      POSTGRES_DB: test
      POSTGRES_USER: test
      POSTGRES_PASSWORD: test
    command:
      - "postgres"
      - "-c"
      - "wal_level=logical"
    volumes:
      - pgdata:/var/lib/postgresql/data
      - ./docker/db:/docker-entrypoint-initdb.d

  test-memcached:
    container_name: test-memcached
    image: memcached

  test-sogo:
    container_name: test-sogo
    depends_on:
      - test-db
      - test-memcached
    build:
      context: test-sogo
    ports:
      # http://localhost:8081/SOGo
      - 8081:80

  test-keycloak:
    container_name: keycloak
    depends_on:
      - test-db
    build:
      context: test-keycloak
    ports:
      - 8088:8080
    environment:
      KC_DB: postgres
      KC_DB_URL: jdbc:postgresql://test-db:5432/test?currentSchema=keycloak
      KC_DB_USERNAME: test
      KC_DB_PASSWORD: test
      KEYCLOAK_FRONTEND_URL: http://localhost:8088/auth
      KEYCLOAK_HOSTNAME_URL: http://test-keycloak:8080
      KEYCLOAK_ADMIN: admin
      KEYCLOAK_ADMIN_PASSWORD: admin
    security_opt:
      - 'label:disable'
    command: [ "start-dev", "--db=postgres" , "--import-realm" ]
      
volumes:
  pgdata:
docker-compose.yml (1,313 bytes)   
Dockerfile (2,320 bytes)   
FROM ubuntu:20.04

# Update all packages and install the apt tools to install the rest
RUN apt update && \
    apt upgrade -y && \
    apt install -y gnupg2 apt-utils ca-certificates apt-transport-https wget

# Add the PGP Key of SOGo
RUN wget -O- "https://keys.openpgp.org/vks/v1/by-fingerprint/74FFC6D72B925A34B5D356BDF8A27B36A6E2EAE9" | gpg --dearmor | apt-key add -

# Download SOGO from this repo:
COPY SOGo.list /etc/apt/sources.list.d/SOGo.list

# Update apt cache and install SOGo
RUN apt update && \
    # Switch to non-interactive install
    export DEBIAN_FRONTEND=noninteractive && \
    # Do the time zone settings beforehand so we don't get promted for it during install (pick your timezone)
    echo "tzdata tzdata/Areas select Europe" | debconf-set-selections && \
    echo "tzdata tzdata/Zones/Europe select Berlin" | debconf-set-selections && \
    echo "tzdata tzdata/Zones/Etc select UTC" | debconf-set-selections && \
    # For some reason SOGo wants this file to be present
    mkdir -p /usr/share/doc/sogo/ && touch /usr/share/doc/sogo/foo.sh && \
    # Install the actual services needed
    apt install -y --no-install-recommends apache2 sope4.9-gdl1-postgresql sogo supervisor gosu && \
    # Prepare non-privileged file permissions for SOGo
    chown sogo /etc/sogo/sogo.conf && \
    mkdir -p /var/run/sogo && chown sogo /var/run/sogo && \
    # Apache also runs on a non-privileged user
    mkdir -p /var/run/apache2 && chown www-data /var/run/apache2 && \
    # Activate the necessary Apache mods and disable the default site
    a2enmod proxy headers proxy_http rewrite && \
    a2dissite 000-default && \
    # Verify that gosu works
    gosu nobody true
    
# This file is explained below
COPY config/supervisord.conf /etc/supervisord/supervisord.conf

COPY config/sogo.conf /etc/sogo/sogo.conf
COPY config/idp-metadata.xml /etc/sogo/idp-metadata.xml
COPY config/saml.key /etc/pki/tls/private/saml.key
COPY config/saml.pem /etc/pki/tls/certs/saml.pem
COPY config/idp.pub /etc/pki/tls/certs/idp.pub
COPY config/idp.pem /etc/pki/tls/certs/idp.pem
RUN chmod 644 /etc/pki/tls/private/saml.key /etc/pki/tls/certs/saml.pem

COPY config/site.conf /etc/apache2/sites-enabled/sogo.conf

# Supervisord will start Apache and SOGo
CMD exec /usr/bin/supervisord -c /etc/supervisord/supervisord.conf
Dockerfile (2,320 bytes)   
jpchev

jpchev

2024-05-03 09:42

reporter   ~0017725

I see the following errors in SOGo logs

sogo | (process:86): Lasso-CRITICAL : 11:38:08.252: 2024-05-03 11:38:08 (profile.c/:939) Trying to unref a non GObject pointer file=profile.c:939 pointerbybname=profile->identity pointer=0x57ea93295f80
sogo |
sogo | (process:86): Lasso-CRITICAL
: 11:38:08.252: 2024-05-03 11:38:08 (profile.c/:942) Trying to unref a non GObject pointer file=profile.c:942 pointerbybname=profile->session pointer=0x57ea93304270

ps I use the release Jammy in a docker image FROM ubuntu:22.04

qhivert

qhivert

2024-05-03 11:51

administrator   ~0017726

Hello,
You still need to define a SOGoUserSource as SAML will be only used for authentication. Maybe the error comes from that.
I've only seen a few people using sogo with saml, you could also search in the mailing list archive for configuration help.
https://www.mail-archive.com/search?q=saml&amp;l=users%40sogo.nu

jpchev

jpchev

2024-05-03 12:34

reporter   ~0017727

thank you for your answer, I think then I don't understand well the product:
as far as I know SOGoUserSource can be plugged either to an ldap server (which I don't have) or to the database,
but I tought all my users can be only on my SAML Idp.

Is it necessary to add an LDAP server? If yes, how to map its users to the users in my SAML idp?

I want to use SOGo only for the shared calendar and so I though I don't need any other idp than my Keycloak

qhivert

qhivert

2024-05-03 12:57

administrator   ~0017728

Well SAML2 is only a protocol for authentication, that's what you have configured in your sogo.conf. But behind the scene keycloak use a user source too, by default a sql database but you can link your keycloak to a ldap server for example.
Sogo needs to have access to this user source, or another one with duplicate or sync data. This usersource will be used for the address books, caldav/cardav...

I don't know how you can manage the keycloak database but maybe the easiest way for you would be to add a table on your postgresql.
SOGoUserSources =
(
{
type = sql;
id = directory;
viewURL = "postgresql://sogo:sogo@127.0.0.1:5432/sogo/sogo_view";
canAuthenticate = NO;
isAddressBook = YES;
}
);

Your table sogo_view must contains

c_uid: - it’s a username or username@domain.tld -> must match the info SOGoSAML2LoginAttribute = &quot;username&quot;;
c_name: will be used to uniquely identify entries - which can be identical to c_uid
c_password: I don't know if this columns is required as it won't be used
c_cn: the user’s common name
mail: the user’s email address

More info here -> https://www.sogo.nu/files/docs/SOGoInstallationGuide.html#Authentication-using-SQL

You could try this to begin.

jpchev

jpchev

2024-05-03 13:31

reporter   ~0017729

I've created the table in postgresql

create table sogo_view(c_uid text, c_name text, c_password text, c_cn text, mail text);

and inserted my user.

Then I set the source

SOGoUserSources = ({
type = sql;
id = directory;
viewURL = "postgresql://sogo:sogo@ase-db:5432/sogo/sogo_view";
canAuthenticate = NO;
isAddressBook = YES;
displayName = "users"
});

(displayName seems important, otherwise I get an error).
I stil have the infinite loop. I don't see in the logs a sql query to my new table sogo_view

Issue History

Date Modified Username Field Change
2024-05-03 08:22 jpchev New Issue
2024-05-03 08:22 jpchev Tag Attached: saml
2024-05-03 08:22 jpchev File Added: site.conf
2024-05-03 08:22 jpchev File Added: sogo.conf
2024-05-03 08:22 jpchev File Added: docker-compose.yml
2024-05-03 08:22 jpchev File Added: Dockerfile
2024-05-03 09:42 jpchev Note Added: 0017725
2024-05-03 11:27 jpchev Tag Attached: docker
2024-05-03 11:27 jpchev Tag Attached: ubuntu
2024-05-03 11:51 qhivert Note Added: 0017726
2024-05-03 11:51 qhivert Assigned To => qhivert
2024-05-03 11:51 qhivert Status new => feedback
2024-05-03 12:34 jpchev Note Added: 0017727
2024-05-03 12:34 jpchev Status feedback => assigned
2024-05-03 12:57 qhivert Note Added: 0017728
2024-05-03 12:58 qhivert Status assigned => feedback
2024-05-03 13:31 jpchev Note Added: 0017729
2024-05-03 13:31 jpchev Status feedback => assigned