Skip to content

Configure tine as Single Sign On identity provider (SSO IdP)

tine can act as SSO identity provider for oidc and SAML2

1) Install SSO application

  • Go to setup.php and make sure SSO is installed
  • In the UI go to Admin > Applications > SSO and make sure SSO is activated
  • Installing SSO will automatically generate the necessary certificates
  • SSO will automatically rotate the certificates every 6 months

2) Generate keys manually

call the tine cli: tine20.php --method=SSO.generateKey

To check if you have valid certificates, you can call these URLs: * https://my.tine.url/sso/saml2/idpmetadata * https://my.tine.url/sso/oauth2/certs

3) Create config

./conf.d/sso.inc.php
<?php

return [
    'SSO' => [
        'pwdLessLogin' => 'both',
        'oauth2' => [
            'enabled' => true,
        ],
        'saml2' => [
            'enabled' => true,
            'tineLogout' => true,
        ],
    ],
];

4) Clear config cache

#! /bin/sh

docker-compose exec --user tine20 web sh -c "cd /usr/share/tine20/ && php setup.php --config=\$TINE20_CONFIG_PATH --clear_cache -v"

5) Configure relaying parties

SSO Relaying parties can be configured per UI in the admin module or via cli using curl

- UI

Go to Admin > Applications > SSO and open the tab RELYING PARTIES in the SSO configuration dialog.

- CLI

Login
#! /bin/sh

URL=http://web:4000/
USER=tine20admin
read PASS

TMP=$(curl -s $URL \
  -H 'Content-Type: application/json' \
  -H 'X-Requested-With: XMLHttpRequest' \
  -H 'X-Tine20-ClientAssetHash: 64558b09a551cee0fac4c9f1dcd5c7a3ac5c0e34' \
  -H 'X-Tine20-Request-Type: JSON' \
  --insecure \
  -d '{"jsonrpc":"2.0","method":"Tinebase.login","params":{"username":"'"$USER"'","password":"'"$PASS"'"},"id":0}' \
  | jq  -r '.result.sessionId, .result.jsonKey')

i=0
for line in $TMP; do
  if [ $i -eq 0 ]; then
    SESSIONID="$line"
  else
    JSONKEY="$line"
  fi
    echo "$line"
    i=$((i+1))
done

export SESSIONID
export JSONKEY

SAML2

The metadata URL of the tine idp (needed in config of the rp) is https://YOURTINEURL/sso/saml2/idpmetadata .

If not given tine fetches the AssertionConsumerService* and singleLogoutService* properties from the optional metaUrl.

Add SAML2 RP
#! /bin/sh

curl $URL \
  -H 'Content-Type: application/json' \
  -H 'Cookie: TINE20SESSID='"$SESSIONID"'' \
  -H 'X-Requested-With: XMLHttpRequest' \
  -H 'X-Tine20-JsonKey: '"$JSONKEY"'' \
  -H 'X-Tine20-Request-Type: JSON' \
  --insecure \
  -d '{"jsonrpc":"2.0","method":"SSO.saveRelyingParty","params":{"recordData":{
    "name": "saml-test-sp",
    "label": "saml-test-sp",
    "description": "you might test with ghcr.io/beryju/saml-test-sp",
    "logo": null,
    "config_class": "SSO_Model_Saml2RPConfig",
    "config": {
      "name": "saml-test-sp",
      "entityid": "saml-test-sp",
      "metaUrl": "http://localhost:4902/saml/metadata",
      "AssertionConsumerServiceBinding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
      "AssertionConsumerServiceLocation": "http://localhost:4902/saml/acs",
      "singleLogoutServiceLocation": "http://localhost:4902/saml/slo",
      "singleLogoutServiceBinding": "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST",
      "attributeMapping": {
        "uid": "accountEmailAddress"
      },
      "customHooks": {
        "postAuthenticate": "/etc/tine20/samlPostAuthHook.php"
      },
      "id": "0"
    }
  },"duplicateCheck":true},"id":3}'

Custom attributes mappings

The mapping tine user attributes => SAML2 attributes can be customized the rp's attributeMapping property (JSON formatted)

Example to map user email to SAML2 uid
{
    "uid": "accountEmailAddress"
}

Custom attributes in SAML response

You can add custom attributes which are sent to the rp see customHooks property (JSON formatted) in the rp config.

Example post auth hook
<?php

// example SAML2 post authenticate hook
// adds the users groups to the attributes
$groupCtrl = Tinebase_Group::getInstance();
$userGroups = $groupCtrl->getMultiple($groupCtrl->getGroupMemberships($user->getId()));
$state['Attributes']['groups'] = array_values($userGroups->name); // value must be an array

oidc

The oicd provider url of the tine idp (needed in the config of the rp) is https://YOURTINEURL (no trailing slash).

Add oidc RP
#! /bin/sh

curl $URL \
  -H 'Accept: */*' \
  -H 'Content-Type: application/json' \
  -H 'Cookie: TINE20SESSID='"$SESSIONID"'' \
  -H 'X-Requested-With: XMLHttpRequest' \
  -H 'X-Tine20-JsonKey: '"$JSONKEY"'' \
  -H 'X-Tine20-Request-Type: JSON' \
  --insecure \
  -d '{"jsonrpc":"2.0","method":"SSO.saveRelyingParty","params":{"recordData":{
    "name": "oidc-test-sp",
    "label": "oidc test service provider",
    "description": "you might test with ghcr.io/beryju/oidc-test-client",
    "logo": "https://openid.net/wordpress-content/uploads/2014/09/openid-r-logo-900x360.png",
    "config_class": "SSO_Model_OAuthOIdRPConfig",
      "config": {
        "redirect_urls": [
          "http://localhost:4901/auth/callback"
        ],
        "secret": "test-secret",
        "is_confidential": false,
        "id": "0"
      }
  },"duplicateCheck":true},"id":3}'

Configure tine as Single Sign On relaying party (SSO RP)

tine can act as SSO relaying party for oidc

1) Install SSO application

  • Go to setup.php and make sure SSO is installed
  • In the UI go to Admin > Applications > SSO and make sure SSO is activated

2) Configure identity providers (IdP)

SSO identity providers can be configured per UI in the admin module or via cli using curl

- UI

Go to Admin > Applications > SSO and open the tab EXTERNAL IDENTITY PROVIDERS in the SSO configuration dialog.

- CLI

Login
#! /bin/sh

URL=http://web:4000/
USER=tine20admin
read PASS

TMP=$(curl -s $URL \
  -H 'Content-Type: application/json' \
  -H 'X-Requested-With: XMLHttpRequest' \
  -H 'X-Tine20-ClientAssetHash: 64558b09a551cee0fac4c9f1dcd5c7a3ac5c0e34' \
  -H 'X-Tine20-Request-Type: JSON' \
  --insecure \
  -d '{"jsonrpc":"2.0","method":"Tinebase.login","params":{"username":"'"$USER"'","password":"'"$PASS"'"},"id":0}' \
  | jq  -r '.result.sessionId, .result.jsonKey')

i=0
for line in $TMP; do
  if [ $i -eq 0 ]; then
    SESSIONID="$line"
  else
    JSONKEY="$line"
  fi
    echo "$line"
    i=$((i+1))
done

export SESSIONID
export JSONKEY
Add foreign mock IDP
#! /bin/sh

curl $URL \
  -H 'Accept: */*' \
  -H 'Content-Type: application/json' \
  -H 'Cookie: TINE20SESSID='"$SESSIONID"'' \
  -H 'X-Requested-With: XMLHttpRequest' \
  -H 'X-Tine20-JsonKey: '"$JSONKEY"'' \
  -H 'X-Tine20-Request-Type: JSON' \
  --insecure \
  -d '{"jsonrpc":"2.0","method":"SSO.saveExternalIdp","params":{"recordData":{
    "name": "oidc-test-idp",
    "config_class": "SSO_Model_ExIdp_OIdConfig",
    "config": {
      "name": "test idp",
      "provider_url": "http://oidc-server-mock:4903",
      "issuer": "http://oidc-server-mock:4903",
      "client_id": "tine20",
      "client_secret": "tine20"
    },
    "domains": [
      {
        "domain": "idp.test"
      }
    ]
  },"duplicateCheck":true},"id":3}'