Last edited 6 hours ago
by Robert Vogel

SAML 2.0 IdP

Revision as of 11:33, 14 July 2026 by Robert Vogel (talk | contribs)

Create the following files and folders within your $DATADIR

└── saml-idp
    ├── saml-config.php
    ├── saml-sp-metadata.php
    └── saml-users.php

Add the following content to the files

saml-config.php

<?php

// See https://github.com/kristophjunge/docker-test-saml-idp/blob/master/config/simplesamlphp/config.php

$idPbaseUrl = 'https://' . getenv( 'DEV_SHARED_IDP_HOST' );
$config = [
	'baseurlpath' => $idPbaseUrl . '/_samlidp/simplesaml/',
	'certdir' => 'cert/',
	'loggingdir' => 'log/',
	'datadir' => 'data/',
	'tempdir' => '/tmp/simplesaml',
	'debug' => true,
	'showerrors' => true,
	'errorreporting' => true,
	'debug.validatexml' => false,
	'auth.adminpassword' => 'secret',
	'admin.protectindexpage' => false,
	'admin.protectmetadata' => false,
	'secretsalt' => 'defaultsecretsalt',
	'technicalcontact_name' => 'Administrator',
	'technicalcontact_email' => 'na@example.invalid',
	'timezone' => NULL,
	'logging.level' => SimpleSAML_Logger::DEBUG,
	'logging.handler' => 'errorlog',
	'logging.facility' => 168,
	'logging.processname' => 'simplesamlphp',
	'logging.logfile' => 'simplesamlphp.log',
	'statistics.out' => [],
	'database.dsn' => 'mysql:host=localhost;dbname=saml',
	'database.username' => 'simplesamlphp',
	'database.password' => 'secret',
	'database.prefix' => '',
	'database.persistent' => false,
	'database.slaves' => [],
	'enable.saml20-idp' => true,
	'enable.shib13-idp' => true,
	'enable.adfs-idp' => false,
	'enable.wsfed-sp' => false,
	'enable.authmemcookie' => false,
	'session.duration' => 28800,
	'session.datastore.timeout' => 14400,
	'session.state.timeout' => 3600,
	'session.cookie.name' => 'SimpleSAMLSessionIDIdp',
	'session.cookie.lifetime' => 0,
	'session.cookie.path' => '/',
	'session.cookie.domain' => NULL,
	'session.cookie.secure' => false,
	'enable.http_post' => false,
	'session.phpsession.cookiename' => 'PHPSESSIDIDP',
	'session.phpsession.savepath' => NULL,
	'session.phpsession.httponly' => true,
	'session.authtoken.cookiename' => 'SimpleSAMLAuthTokenIdp',
	'session.rememberme.enable' => false,
	'session.rememberme.checked' => false,
	'session.rememberme.lifetime' => 1209600,
	'language.available' =>
	[
		0 => 'en',
		1 => 'no',
		2 => 'nn',
		3 => 'se',
		4 => 'da',
		5 => 'de',
		6 => 'sv',
		7 => 'fi',
		8 => 'es',
		9 => 'fr',
		10 => 'it',
		11 => 'nl',
		12 => 'lb',
		13 => 'cs',
		14 => 'sl',
		15 => 'lt',
		16 => 'hr',
		17 => 'hu',
		18 => 'pl',
		19 => 'pt',
		20 => 'pt-br',
		21 => 'tr',
		22 => 'ja',
		23 => 'zh',
		24 => 'zh-tw',
		25 => 'ru',
		26 => 'et',
		27 => 'he',
		28 => 'id',
		29 => 'sr',
		30 => 'lv',
		31 => 'ro',
		32 => 'eu',
	],
	'language.rtl' =>
	[
		0 => 'ar',
		1 => 'dv',
		2 => 'fa',
		3 => 'ur',
		4 => 'he',
	],
	'language.default' => 'en',
	'language.parameter.name' => 'language',
	'language.parameter.setcookie' => true,
	'language.cookie.name' => 'language',
	'language.cookie.domain' => NULL,
	'language.cookie.path' => '/',
	'language.cookie.lifetime' => 77760000,
	'attributes.extradictionary' => NULL,
	'theme.use' => 'default',
	'default-wsfed-idp' => 'urn:federation:pingfederate:localhost',
	'idpdisco.enableremember' => true,
	'idpdisco.rememberchecked' => true,
	'idpdisco.validate' => true,
	'idpdisco.extDiscoveryStorage' => NULL,
	'idpdisco.layout' => 'dropdown',
	'shib13.signresponse' => true,
	'authproc.idp' =>
	[
		30 => 'core:LanguageAdaptor',
		45 =>
		[
			'class' => 'core:StatisticsWithAttribute',
			'attributename' => 'realm',
			'type' => 'saml20-idp-SSO',
		],
		50 => 'core:AttributeLimit',
		99 => 'core:LanguageAdaptor',
	],
	'authproc.sp' =>
	[
		90 => 'core:LanguageAdaptor',
	],
	'metadata.sources' =>
	[
		[
			'type' => 'flatfile',
		],
	],
	'store.type' => 'phpsession',
	'store.sql.dsn' => 'sqlite:/path/to/sqlitedatabase.sq3',
	'store.sql.username' => NULL,
	'store.sql.password' => NULL,
	'store.sql.prefix' => 'SimpleSAMLphp',
	'memcache_store.servers' =>
	[
		[
			[
				'hostname' => 'localhost',
			],
		],
	],
	'memcache_store.prefix' => NULL,
	'memcache_store.expires' => 129600,
	'metadata.sign.enable' => false,
	'metadata.sign.privatekey' => NULL,
	'metadata.sign.privatekey_pass' => NULL,
	'metadata.sign.certificate' => NULL,
	'proxy' => NULL,
	'trusted.url.domains' => [],
];

saml-sp-metadata.php

<?php

#SIMPLESAMLPHP_SP_ENTITY_ID: https://${DEV_SHARED_IDP_HOST}/simplesaml/saml2/idp/metadata.php
#SIMPLESAMLPHP_SP_ASSERTION_CONSUMER_SERVICE: https://${DEV_PROD_EU_HOST}/_sp/module.php/saml/sp/saml2-acs.php/default-sp
#SIMPLESAMLPHP_SP_SINGLE_LOGOUT_SERVICE: https://${DEV_PROD_EU_HOST}/_sp/module.php/saml/sp/saml2-logout.php/default-sp

# Test authn: https://mydev.localhost/_sp/module.php/admin/test/default-sp

$idpHost = getenv( 'DEV_SHARED_IDP_HOST' );
$spHosts = getenv( 'DEV_SP_HOSTS' ) ?? '';
$spHosts = explode( ',', $spHosts );
$spHosts = array_map( 'trim', $spHosts );

$metadata = [];

foreach ( $spHosts as $spHostAndName ) {
	$spParts = explode( '###', $spHostAndName );
	$spHost = $spParts[0];
	$spName = $spParts[1];
	$metadata["https://$spHost"] = array(
		'AssertionConsumerService' => "https://$spHost/_sp/module.php/saml/sp/saml2-acs.php/$spName",
		'SingleLogoutService' => "https://$spHost/_sp/module.php/saml/sp/saml2-logout.php/$spName",
	);
}

saml-users.php

<?php

// See https://github.com/kristophjunge/docker-test-saml-idp/blob/master/config/simplesamlphp/authsources.php

$pass = getenv( 'DB_ROOT_PASS' );

$config = [
	'admin' => [
		'core:AdminPassword',
	],
	'example-userpass' => [
		// First element must be a string which identifies the authentication source.
		'exampleauth:UserPass',

		"alice@example.invalid:$pass" => [
			'username' => [ 'alice@example.invalid' ],
			'name' => [ 'Alice' ],
			'email' => [ 'alice@example.invalid' ],
			'groups' => [ 'wiki-contributor', 'wiki-admin' ]
		],
		"bob@example.invalid:$pass" => [
			'username' => [ 'bob@example.invalid' ],
			'name' => [ 'Bob' ],
			'email' => [ 'bob@example.invalid' ],
			'groups' => [ 'wiki-contributor' ]
		],
		"charlie@example.invalid:$pass" => [
			'username' => [ 'charlie@example.invalid' ],
			'name' => [ 'Charlie' ],
			'email' => [ 'charlie@example.invalid' ],
			'groups' => [ 'wiki-admin' ]
		]
	],
];


In your docker-compose.override.yml add

  samlidp:
    image: kristophjunge/test-saml-idp
    container_name: ${COMPOSE_PROJECT_NAME:-bluespice}-samlidp
    volumes:
      - ${DATADIR}/saml-idp/saml-config.php:/var/www/simplesamlphp/config/config.php
      - ${DATADIR}/saml-idp/saml-users.php:/var/www/simplesamlphp/config/authsources.php
      - ${DATADIR}/saml-idp/saml-sp-metadata.php:/var/www/simplesamlphp/metadata/saml20-sp-remote.php
    environment:
      VIRTUAL_HOST: ${WIKI_HOST}
      VIRTUAL_PATH: /_samlidp/
      VIRTUAL_PORT: 8080
      VIRTUAL_DEST: /
      DEV_SHARED_IDP_HOST: ${WIKI_HOST}
      DEV_SP_HOSTS: ${WIKI_HOST}###default-sp
    restart: no

After starting the stack with ./bluespice-deploy up -d you can

To wire your wiki application, create a new file settings.d/099-SAML-dev.local.php within your $CODEDIR

<?php

$GLOBALS['wgExtensionFunctions'][] = function () {
	$GLOBALS['wgPluggableAuth_EnableAutoLogin'] = true;
	$GLOBALS['wgPluggableAuth_Config']['Log in with SAML'] = [
		'plugin' => 'SimpleSAMLphp',
		'data' => [
			'authSourceId' => 'default-sp',
			'usernameAttribute' => 'name',
			'realNameAttribute' => 'name',
			'emailAttribute' => 'email'
		],
		'groupsyncs' => [
			[
				'type' => 'mapped',
					'map' => [
						'editor' => [
							'groups' => 'wiki-contributor'
						],
						'sysop' => [
							'groups' => 'wiki-admin'
						]
					]
			]
		]

	];
};


PDF exclude - start

To submit feedback about this documentation, visit our community forum.

PDF exclude - end