Keycloak IdP for SSO

To explore : http://www.keycloak.org/docs/latest/securing_apps/index.html#_mod_auth_openidc

official website

Server IdP ( identity provider) for the SSO (single sign-on) Application written in Java, runs on a WildFly server.

Installation and configuration

Pre requises (see documentation) :

Fetch the software :

sudo su
add-apt-repository ppa:webupd8team/java
apt update
apt install default-jre oracle-java8-installer

Fetch the software :

cd /var/www
wget https://downloads.jboss.org/keycloak/xxx.Final/keycloak-xxx.Final.zip
unzip keycloak-xxx.Final.zip -d .
cd keycloak-xxx.Final
wget https://downloads.jboss.org/keycloak/xxx.Final/adapters/keycloak-oidc/keycloak-wildfly-adapter-dist-xxx.Final.zip
unzip keycloak-wildfly-adapter-dist-xxx.Final.zip -d .
wget https://downloads.jboss.org/keycloak/xxx.Final/keycloak-proxy-xxx.Final.zip
unzip keycloak-proxy-xxxFinal.zip -d .
rm *.zip

Add the user admin :

./bin/add-user-keycloak.sh -u username

if it returns the message No content to map due to end-of-input, then create a temporary admin user tempuser with the password dkPK62wdofPEK56-_&SO :

nano ./standalone/configuration/keycloak-add-user.json

Put this :

[ {
  "realm" : "master",
  "users" : [{
    "username" : "tempuser",
    "enabled" : true,
    "emailVerified" : true,
    "credentials" : [ {
      "type" : "password",
      "hashedSaltedValue" : "IhS5rpj4PV20PURXYtQktPAYDbI5ATQdafxquCWs1mKwJtuvxhW2DQ0QGNuaQV42MXLSkrLeAyjf4UzlIxm04g==",
      "salt" : "wue854XfHBduqKFcgm9tNQ==",
      "hashIterations" : 100000,
      "algorithm" : "pbkdf2-sha256"
    } ],
    "realmRoles" : [ "admin" ]
  } ]
} ]

Start the server :

./bin/standalone.sh

When you experience an error at startup, check if it is not a port which is already taken, like port 8080 (we use 8081) or 9990 (we use 9991) In tat case change the config file (at the end) :

nano standalone/configuration/standalone.xml

Access server from outside

Open the ports (adapt the numbers) :

ufw allow 8081
ufw allow 9991

Launch the server on the IP of the network card of the machine :

ifconfig

note the IP of the network card (network adapter)

nano standalone/configuration/standalone.xml

search this phrase : jboss.bind.address.management: and change 127.0.0.1 with the IP address of the network card. Idem for jboss.bind.address

Start the server and go to the address x.x.x.x:8081

Configure SSL to access to the server with HTTPS (apache reverse proxy method)

sudo a2enmod headers
cd /etc/apache2/sites-available

Create the file keycloak.domain.ext.conf

<VirtualHost *:80>
        ServerName keycloak.domain.ext
        ServerAdmin email@domain.ext

        ProxyPass / http://000.000.000.000:8081/
        ProxyPassReverse / http://000.000.000.000:8081/
        ProxyRequests Off
        ProxyPreserveHost Off

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
a2ensite keycloak.domain.ext.conf 
service apache2 reload
certbot --apache -d keycloak.domain.ext

Edit keycloak.domain.ext.conf and add inside the <VirtualHost *:443> tag :

        ProxyPreserveHost On
        SSLProxyEngine On
        SSLProxyCheckPeerCN on
        SSLProxyCheckPeerExpire on
        RequestHeader set X-Forwarded-Proto "https"
        RequestHeader set X-Forwarded-Port "443"
service apache2 reload
``


### Configure SSL to access to the server with HTTPS (depreciated method because 8433 port is not reachable by everyone)

1- `nano /usr/local/bin/renew.sh` and put (adjust the 3 variables, YOURPASSWORD musn't contain any special char or space) :

!/bin/sh

SITE=domain.ext YOURPASSWORD=xxxxxxxxx

for LETSENCRYPTPATH, check the lastest path corresponding to domain.ext. It can be just domain.ext, or domain.ext-0001, or domain.ext-0002, etc.

LETSENCRYPTPATH=domain.ext-0001 KEYCLOAKPATH=/var/www/keycloak

Create the SSL cerficat with Lets'Encrypt

certbot certonly --renew-by-default --standalone -d $SITE --pre-hook "service apache2 stop" --post-hook "service apache2 start"

move to the correct let's encrypt directory

cd /etc/letsencrypt/live/$LETSENCRYPTPATH

copy the files

cp cert.pem /etc/ssl/certs/$SITE.cert.pem cp fullchain.pem /etc/ssl/certs/$SITE.fullchain.pem cp privkey.pem /etc/ssl/private/$SITE.privkey.pem

adjust permissions of the private key

chown :ssl-cert /etc/ssl/private/$SITE.privkey.pem chmod 640 /etc/ssl/private/$SITE.privkey.pem

Add certificate to Wildfly for Keycloak

rm cert_and_key.pkcs12 rm keycloak.jks

Merge the public keys, intermediate and private in a file pkcs12

openssl pkcs12 -export -in fullchain.pem -inkey privkey.pem -out cert_and_key.pkcs12 -CAfile chain.pem -caname root -name $SITE -password pass:secret

Generate the file jks (for java) from the pkcs12 and assign the passwords

keytool -importkeystore -srckeystore cert_and_key.pkcs12 -srcstoretype PKCS12 -srcstorepass secret -destkeystore keycloak.jks -deststorepass $YOURPASSWORD -destkeypass $YOURPASSWORD

Copy this file into the Keycloak config folder

cp keycloak.jks $KEYCLOAKPATH/standalone/configuration


2- Make the script readable and execute it :

chmod +x /usr/local/bin/renew.sh /usr/local/bin/renew.sh


3- Remember to manually execute it before certificate expiration and reload Keycloak after running `/usr/local/bin/renew.sh`

4- Configure WildFly to accept HTTPS requests
cd /var/www/keycloak/keycloak-xxx.Final
nano standalone/configuration/standalone.xml

For Keycloak 3.2, add the following lines inside `<security-realms> ... </security-realms>` and replace YOURPASSWORD :
<security-realm name="UndertowRealm">
    <server-identities>
        <ssl>
            <keystore path="keycloak.jks" relative-to="jboss.server.config.dir" keystore-password="YOURPASSWORD" />
        </ssl>
    </server-identities>
</security-realm>
For Keycloak 3.3, replace

with:


Replace

with:
<http-listener name="default" socket-binding="http" proxy-address-forwarding="true" redirect-socket="proxy-https" />

Add the following line inside `<socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}"> ... </socket-binding-group>` :
<socket-binding name="proxy-https" port="443"/>

If needed : http://www.keycloak.org/docs/latest/server_installation/index.html#_network

6- Open port 8443 in the firewall and start the server

ufw allow 8443

Access the server here : https://domain.ext:8443

## Configure the MySQL database
[Official documentation](https://keycloak.gitbooks.io/documentation/content/server_installation/topics/database.html)

sudo su cd /var/www/keycloak mkdir ./modules/system/layers/keycloak/org/mysql mkdir ./modules/system/layers/keycloak/org/mysql/main


Download [the Java module of MySQL](https://dev.mysql.com/downloads/connector/j/)
Unzip and copy the file `mysql-connector-java-x.x.x-bin.jar` to `./modules/system/layers/keycloak/org/mysql/main` then rename it to `mysql-connector-java-bin.jar` and make it executable : `chmod +x modules/system/layers/keycloak/org/mysql/main/mysql-connector-java-bin.jar`

Create the file `/{DOSSIER-KEYCLOAK}/modules/system/layers/keycloak/org/mysql/main/module.xml` and put :

<?xml version="1.0" ?>

<resources>
    <resource-root path="mysql-connector-java-bin.jar"/>
</resources>

<dependencies>
    <module name="javax.api"/>
    <module name="javax.transaction.api"/>
</dependencies>

</module>


Create the database `idp_keycloak` (don't use `-` char) with `utf8_general_ci`, create user `idp-keycloak` and give him the rights of this this base.

Caution ! Avoid special characters in the MySQL password like the `&` char.

Edit the file `standalone/configuration/standalone.xml`, replace what is between  `<subsystem xmlns="urn:jboss:domain:datasources:x.x">` and `</subsystem>` with (replace MYSQL-USER-PASSWORD) :
        <datasources>
            <datasource jndi-name="java:jboss/datasources/KeycloakDS" pool-name="KeycloakDS" enabled="true" use-java-context="true">
               <connection-url>/idp_keycloak?useSSL=false</connection-url>
               <driver>mysql</driver>
               <pool>
                   <max-pool-size>20</max-pool-size>
               </pool>
               <security>
                   <user-name>idp_keycloak</user-name>
                   <password>MYSQL-USER-PASSWORD</password>
               </security>
            </datasource>
            <datasource jndi-name="java:jboss/datasources/ExampleDS" pool-name="ExampleDS" enabled="true" use-java-context="true">
                <connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE</connection-url>
                <driver>h2</driver>
                <security>
                    <user-name>sa</user-name>
                    <password>sa</password>
                </security>
            </datasource>
            <drivers>
                <driver name="mysql" module="org.mysql">
                    <xa-datasource-class>org.mysql.xa.PGXADataSource</xa-datasource-class>
                </driver>
                <driver name="h2" module="com.h2database.h2">
                    <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
                </driver>
            </drivers>
        </datasources>

Then, before restarting the server, add again a new admin user  (because he was registered in the old database) :
bin/add-user-keycloak.sh -u username

### Launch the Widfly server when the machine starts

sudo nano /etc/rc.local


and add :
`/var/www/keycloak/keycloak-server/bin/standalone.sh &`

## Currently under development 
https://keycloak.gitbooks.io/documentation/getting_started/topics/secure-jboss-app/install-client-adapter.html
cd /var/www/keycloak
wget https://downloads.jboss.org/keycloak/3.2.1.Final/adapters/keycloak-oidc/keycloak-wildfly-adapter-dist-3.2.1.Final.zip
unzip keycloak-wildfly-adapter-dist-3.2.1.Final.zip -d .
rm keycloak-wildfly-adapter-dist-3.2.1.Final.zip
cd bin
./jboss-cli.sh --file=adapter-install-offline.cli


## Add an IdP provider

[Example with Facebook](https://symbiotics.co.za/keycloak-social-login-and-sso-solution/)


## Realm configuration

Configure :
- Realm settings :
  - Login : all "on" except "email as username" or "Edit username" ; require SSL -> all requests
  - Email
  - Theme : enable internationalization and select "fr" only
  - Security Defenses (if iframe) : replace Content-Security-Policy by `frame-src 'self' domain.ext sub.domain.ext; frame-ancestors 'self' domain.ext sub.domain.ext; object-src 'self' domain.ext sub.domain.ext;`
  - Tokens : SSO session max : 365 days / Offline Session Idle : 400 days
- Authentification :
  - Passowrd Policy : Digits 1 / Minimum Length : 8 / Not Username / Uppercase Characters : 1


## Mass import users

Create a json file containing, for example (password is `dkPK62wdofPEK56-_&SO`) :

{ "realm": "master", "users" : [ { "username" : "test1", "email" : "test1@mail.ext", "firstName" : "Toto1", "lastName" : "Titi1", "enabled" : true, "emailVerified" : true, "credentials" : [ { "type" : "password", "hashedSaltedValue" : "IhS5rpj4PV20PURXYtQktPAYDbI5ATQdafxquCWs1mKwJtuvxhW2DQ0QGNuaQV42MXLSkrLeAyjf4UzlIxm04g==", "salt" : "wue854XfHBduqKFcgm9tNQ==", "hashIterations" : 100000, "algorithm" : "pbkdf2-sha256" } ], "realmRoles" : [ "offline_access", "uma_authorization" ] }, { "username" : "test2", "email" : "test2@mail.ext", "firstName" : "Toto2", "lastName" : "Titi2", "enabled" : true, "emailVerified" : true, "credentials" : [ { "type" : "password", "hashedSaltedValue" : "IhS5rpj4PV20PURXYtQktPAYDbI5ATQdafxquCWs1mKwJtuvxhW2DQ0QGNuaQV42MXLSkrLeAyjf4UzlIxm04g==", "salt" : "wue854XfHBduqKFcgm9tNQ==", "hashIterations" : 100000, "algorithm" : "pbkdf2-sha256" } ], "realmRoles" : [ "offline_access", "uma_authorization" ] } ] }


And import it in the admin user interface (Manage -> Import)

## Create a new client

Infos : https://domain.ext:8443/auth/realms/master/.well-known/openid-configuration

More info :
- https://www.infoq.com/fr/articles/introduction-openid-connect
- http://www.keycloak.org/docs-api/3.2/rest-api/

The Reaml X.509 Certificate can be found in Realm settings -> Keys -> Certificate

Logout URL : https://domain.ext:8443/auth/realms/master/protocol/openid-connect/logout?redirect_uri=encodedURL


### OpenId Connect

- Client Protocol : openid-connect
- Access Type : confidential
- Standard Flow Enabled : ON
- Implicit Flow Enabled : OFF
- Direct Access Grants Enabled : ON
- Service Accounts Enabled : OFF
- Authorization Enabled : OFF
- Root URL : htts://domain.ext
- Valid Redirect URIs : htts://domain.ext/*
- Fine Grain OpenID Connect Configuration :
    - User Info Signed Response Algorithm : unsigned
    - Request Object Signature Algorithm : any

### Wordpress OpenID Connect Login

1. Create an OpenId Connect client
2. [Install OpenId Connect Generic plugin](https://github.com/daggerhart/openid-connect-generic)
3. Configure :
  - copy/paste the examples (For "OpenID Scope" ([more info here](https://openid.net/specs/openid-connect-basic-1_0.html#Scopes))
  - for the URLs : https://domain.ext:8443/auth/realms/master/.well-known/openid-configuration (Login Endpoint URL = .../auth)
  - check "Identify with User Name, "Link Existing Users", "Redirect Back to Origin Page" and "Alternate Redirect URI"
  - for "Identity Key" : if you connect with a username, use `preferred_username` otherwise use Keyclok id : `sub` for the Identity Key
4. Go to "Settings" -> "Permalinks" and save again the configuration (even if no changes)
5. Add the button : `[openid_connect_generic_login_button]`
6. In `openid-connect-generic-client-wrapper.php` : replace the pattern of `preg_replace` by `'/[^a-zA-Z\-\_0-9]/'`
7. In `openid-connect-generic-login-form.php` : replace `Login with OpenID Connect` by `Login / Sign up`
8. in `openid-connect-generic-client.php` : 
  - remove all the if after `// check the client request state `
  - replace :
    `$id_token_claim = json_decode( base64_decode( $tmp[1] ), TRUE );`
    by :
    $id_token_claim = json_decode(
        base64_decode(
            str_replace( // because token is encoded in base64 URL (and not just base64)
                array('-', '_'),
                array('+', '/'),
                $tmp[1]
            )
        )
        , TRUE
    );

If doesn't work because of "cURL connection refused" see [this workaround](https://www.digitalocean.com/community/questions/wordpress-wp-cron-curl-connection-refused)

If you want users to connect to Wordpress throw an iframe, add this in the theme `function.php` :

// Allow to connect from an iframe remove_action( 'login_init', 'send_frame_options_header' ); remove_action( 'admin_init', 'send_frame_options_header' );


### Wordpress SAML OneLogin plugin

> Change "master" with your Realm name if different, and 8443 with your custom port if different

In OneLogin settings :

- IdP Identity id : https://URL:8443/auth/realms/master
- Single Sign On Service Url : https://URL:8443/auth/realms/master/protocol/saml
- X.509 Certificate : Keycloak -> Realm settings -> Keys -> Certificate
- ATTRIBUTE MAPPING : 
    - Username : username
    - E-mail : email
    - First Name : first_name
    - Last Name : last_name
    - Role : Role
- ROLE PRECEDENCE : Administrator : 1, Editor : 2, etc.
- Service Provider Entity Id : Keycloak -> Client -> Client ID
- Sign AuthnRequest : Checked
- Sign LogoutRequest : Checked
- Sign LogoutResponse : Checked
- NameIDFormat : ... SAML:2.0  ... persistent
- Service Provider X.509 Certificate & Service Provider Private Key : put a temporary cerficificate
- Signature Algorithm & Digest Algorithm: RSA_SHA256

Click on "Go to the metadata of this SP" (top right) : download in a XML file

In KeyCloak : add a new client

- Select file : the XML file and save

If you need to configure manually :

- Client Id : give any custom name
- Save
- Client protocol : SAML
- Include AuthnStatement : ON
- Sign Documents : ON
- Signature Algorithm : RSA_SHA256
- Canonicalization Method : EXCLUSIVE
- Client Signature Required : ON
- Force POST Binding : ON
- Front Channel Logout : ON
- Name ID Format : persistent
- Valid Redirect URIs : https://wordpress_URL/wp-login.php?saml_acs
- Fine Grain SAML Endpoint Configuration :
    - Assertion Consumer Service POST Binding URL : https://wordpress_URL/wp-login.php?saml_acs
    - Logout Service Redirect Binding URL : https://wordpress_URL/wp-login.php?saml_sls

Tab Mappers

- Roles list -> edit :
    - Role attribute name : Role
    - SAML Attribute NameFormat : unspecified
    - Single Role Attribute : ON
- Create :
    - Name : username
    - Mapper Type : User Property
    - Property : username
    - Friendly Name : username
    - SAML Attribute Name : username
    - SAML Attribute NameFormat : unspecified
- Create again for : email, first_name, last_name


Keycloak -> Client -> Client Id -> SAML Keys -> Generate new keys

Copy values in Onelogin plugin -> Service Provider X.509 Certificate & Service Provider Private Key

### OpenID-Connect-PHP

[OpenID-Connect-PHP GitHub repository](https://github.com/jumbojett/OpenID-Connect-PHP)

It's a simple library that allows an application to authenticate a user through the basic OpenID Connect flow.


Install :

composer require jumbojett/openid-connect-php


Create a test script `test.php`

<?php ini_set('display_errors', 1); ini_set('display_startup_errors', 1); error_reporting(E_ALL);

require "./vendor/autoload.php";

$oidc = new OpenIDConnectClient('https://idp.make.social:8443/auth/realms/master', 'OpenID-Connect-PHP', 'b16fbf2b-7aa3-4f02-a488-d3e04f26cb3e');

$oidc->authenticate(); $userInfo = $oidc->requestUserInfo(); $name = $userInfo->preferred_username; // see KeyCloak client Mappers tab (field "Token Claim Name") ?>

Example OpenID Connect Client Use

<div>
    <p>Hello <?php echo $name; ?></p>
    <p>UserInfo array : <?php print_r($userInfo); ?></p>
</div>

</body> </html>


### Yii2 OpenIdConnect


#### Install

[Source](https://github.com/yiisoft/yii2-authclient/blob/master/docs/guide/installation.md)

composer require --prefer-dist yiisoft/yii2-authclient "~2.1.0"


Edit `config/web.php` and add in 'compenents' :
    'authClientCollection' => [
        'class' => 'yii\authclient\Collection',
        'clients' => [
            'YourName' => [
                'class' => 'yii\authclient\clients\Keycloak',
                'issuerUrl' => 'https://domain.ext:8443/auth/realms/master',
                'clientId' => 'KeycloakClientId',
                'clientSecret' => '*************',
            ],
        ],
    ],


#### Start

[Source](https://github.com/yiisoft/yii2-authclient/blob/master/docs/guide/quick-start.md)

Open the file `controllers/SiteController.php`, add `use app\components\AuthHandler;` at the beginning of the file, and theses 2 functions inside `class SiteController extends Controller` :
public function actions()
{
    return [
        'auth' => [
            'class' => 'yii\authclient\AuthAction',
            'successCallback' => [$this, 'onAuthSuccess'],
        ],
    ];
}

public function onAuthSuccess($client)
{
    (new AuthHandler($client))->handle();
}

The class `class AuthHandler` must be in `components/AuthHandler.php` (create components folder if not exist) and create the file `AuthHandler.php` containing the implementation describe [here](https://github.com/yiisoft/yii2-authclient/blob/master/docs/guide/quick-start.md)

Add the widget in a view file (eg. `views/site/login.php`) :

<?= yii\authclient\widgets\AuthChoice::widget([ 'baseAuthUrl' => ['site/auth'], 'popupMode' => false, ]) ?>


#### Install OpenId Connect

[Source](https://github.com/yiisoft/yii2-authclient/blob/master/docs/guide/open-id-connect.md)

sudo apt update; sudo apt install libgmp-dev php-gmp; sudo service apache2 reload; composer require --prefer-dist "spomky-labs/jose:~5.0.6"


The class OpenIdConnect extends OAuth2
See [OpenId Connect specifications](http://www.yiiframework.com/doc-2.0/yii-authclient-openidconnect.html)


#### Create the Auth.php file if not exist

`nano models/Auth.php` :

<?php namespace app\models; use Yii; class Auth extends \yii\db\ActiveRecord { public static function tableName() { return 'user_auth'; }

public function rules()
{
    return [
        ['user_id', 'source', 'source_id'], 'required'],
        ]('user_id',-'source',-'source_id'],-'required'],

------------.html)'user_id'], 'integer'], ['source', 'source_id'], 'string', 'max' => 255] ]; }

public function attributeLabels()
{
    return [
        'id' => 'ID',
        'user_id' => 'User ID',
        'source' => 'Source',
        'source_id' => 'Source ID',
    ];
}

public function getUser()
{
    return $this->hasOne(User::className(), ['id' => 'user_id']);
}

}


#### [Create a Keycloak client](https://github.com/yiisoft/yii2-authclient/blob/master/docs/guide/creating-your-own-auth-clients.md)

Create the file `vendor/yiisoft/yii2-authclient/clients/Keycloak.php` containing :

<?php

namespace yii\authclient\clients;

use yii\authclient\OpenIdConnect;

class Keycloak extends OpenIdConnect { public function applyAccessTokenToRequest($request, $accessToken) { $data = $request->getData(); $data['Authorization'] = 'Bearer ' . $accessToken->getToken(); $request->setHeaders($data); }

protected function defaultName()
{
    return 'keycloak';
}

protected function defaultTitle()
{
    return 'Centralized authentification';
}

}


#### Debug

vendor/yiisoft/yii2-authclient/OpenIdConnect.php

At the end of `function requestTokens($code)` :

$return = parent::fetchAccessToken($authCode, $params); file_put_contents("/var/www/test.make.social/public_html/test.txt", serialize($return)); return $return;


`cat /var/www/test.make.social/public_html/test.txt`

Copy and paste the token (just after `access_token";s:1746:"`) in https://jwt.io/


### Node.Js with Oauth2

https://adodson.com/hello.js


### Symfony OpenIdConnect

1. Install [Symfony 2.8 demo](https://github.com/symfony/demo/releases/tag/v0.8.3)
2. Install [OpenId Connect Relying Party Bundle](https://github.com/waldo2188/OpenIdConnectRelyingPartyBundle/blob/master/Resources/doc/index.md) but replace `"gree/jose": "0.1.7"` with `"gree/jose" : "~2.0"`

Example of config for :
base_url: "https://sso-synfony.marc.fun"
client_id: "sso-symfony-marc-fun"         #OpenID Connect client id given by the OpenId Connect Provider
client_secret: "xxxxxxxx-xxxx-xxxx-xxxxx-xxxxxxxx" #OpenID Connect client secret given by the OpenId Connect Provider
issuer: "https://login.lescommuns.org:8443/auth/realms/master/protocol/openid-connect" #URL of the OpenID Connect Provider
endpoints_url:                  #Part of the URL of the OpenID Connect Provider
    authorization: "/auth"
    token: "/token"
    userinfo: "/userinfo"
    logout: "/logout"
display: "page"                   #How the authentication form will be display to the enduser
scope: "email profile openid offline_access" #List of the scope you need
authentication_ttl: 300         #Maximum age of the authentication
token_ttl: 300                  #Maximum age for tokenID
jwk_url: "https://login.lescommuns.org:8443/auth/realms/master/protocol/openid-connect/certs" #URL to the Json Web Key of OpenID Connect Provider
jwk_cache_ttl: 86400             #Validity periods in second where the JWK store in cache is valid
enabled_state: true             #Enable the use of the state value. This is useful for mitigate replay attack
enabled_nonce: true             #Enable the use of the nonce value. This is useful for mitigate replay attack
enduserinfo_request_method: "POST" #Define the method (POST, GET) used to request the Enduserinfo Endpoint of the OIDC Provider
redirect_after_logout: "https://sso-synfony.marc.fun"           #URI or route name used for redirect user after a logout

Edit `vendor/waldo/openid-connect-relying-party-bundle/Waldo/OpenIdConnect/RelyingPartyBundle/OpenIdConnect/Constraint/IDTokenValidator.php` and comment `$this->errors[] = "Issuer are not the same";` because Keycloak return "https://login.lescommuns.org:8443/auth/realms/master" and the script is comparing to the value of the issuer in `config.yml` wich is "https://login.lescommuns.org:8443/auth/realms/master/protocol/openid-connect"

To show the result of SSO, edit `vendor/waldo/openid-connect-relying-party-bundle/Waldo/OpenIdConnect/RelyingPartyBundle/OpenIdConnect/ResourceOwner/AbstractGenericOICResourceOwner.php` and after `$oicToken->setRawTokenData($content);` add :

echo '

'; print_r($content); echo '
'; exit;


The logout URL is `<a href="{{ path('_oic_rp_logout') }}">Logout</a>`

## Links to explore

- http://blog.keycloak.org/2015/04/running-keycloak-cluster-with-docker.html
- http://rhelblog.redhat.com/2016/03/22/red-hat-federation-story-ipsilon-keycloak-a-clash-of-the-titans/
- http://rhelblog.redhat.com/2016/04/26/why-use-sssd-instead-of-a-direct-ldap-configuration-for-applications/
- https://keycloak.gitbooks.io/server-adminstration-guide/content/topics/user-federation/sssd.html
- https://keycloak.gitbooks.io/securing-client-applications-guide/content/topics/oidc/javascript-adapter.html
- https://github.com/keycloak/keycloak-js-bower
- https://keycloak.gitbooks.io/securing-client-applications-guide/content/topics/oidc/nodejs-adapter.html
- https://github.com/keycloak/keycloak-nodejs-connect
- https://github.com/keycloak/keycloak-nodejs-auth-utils
- http://blog.keycloak.org/2015/08/improved-ldap-integration-with-keycloak.html
- http://keycloak-user.88327.x6.nabble.com/keycloak-user-Create-user-from-keycloak-UI-with-FreeIPA-backend-td1653.html
]('source',-'source_id'],-'string',-'max'-=>-255]
--------];
----}

----public-function-attributelabels()
----{
--------return-[
------------'id'-=>-'id',
------------'user_id'-=>-'user-id',
------------'source'-=>-'source',
------------'source_id'-=>-'source-id',
--------];
----}

----public-function-getuser()
----{
--------return-$this->hasone(user::classname(),-['id'-=>-'user_id']);
----}
}

-create-a-keycloak-client

create-the-file-vendor/yiisoft/yii2-authclient/clients/keycloak.php-containing-:

<?php

namespace-yii\authclient\clients;

use-yii\authclient\openidconnect;

class-keycloak-extends-openidconnect
{
----public-function-applyaccesstokentorequest($request,-$accesstoken)
----{
--------$data-=-$request->getdata();
--------$data['authorization']-=-'bearer-'-.-$accesstoken->gettoken();
--------$request->setheaders($data);
----}


----protected-function-defaultname()
----{
--------return-'keycloak';
----}

----protected-function-defaulttitle()
----{
--------return-'centralized-authentification';
----}
}

-debug

vendor/yiisoft/yii2-authclient/openidconnect.php

at-the-end-of-function-requesttokens($code)-:

$return-=-parent::fetchaccesstoken($authcode,-$params);
file_put_contents("/var/www/test.make.social/public_html/test.txt",-serialize($return));
return-$return;

cat-/var/www/test.make.social/public_html/test.txt

copy-and-paste-the-token-(just-after-access_token";s:1746:")-in-https://jwt.io/

-node.js-with-oauth2

https://adodson.com/hello.js

-symfony-openidconnect

1.-install-symfony-2.8-demo 2.-install-openid-connect-relying-party-bundle-but-replace-"gree/jose":-"0.1.7"-with-"gree/jose"-:-"~2.0"

example-of-config-for-:

----base_url:-"https://sso-synfony.marc.fun"
----client_id:-"sso-symfony-marc-fun"---------#openid-connect-client-id-given-by-the-openid-connect-provider
----client_secret:-"xxxxxxxx-xxxx-xxxx-xxxxx-xxxxxxxx"-#openid-connect-client-secret-given-by-the-openid-connect-provider
----issuer:-"https://login.lescommuns.org:8443/auth/realms/master/protocol/openid-connect"-#url-of-the-openid-connect-provider
----endpoints_url:------------------#part-of-the-url-of-the-openid-connect-provider
--------authorization:-"/auth"
--------token:-"/token"
--------userinfo:-"/userinfo"
--------logout:-"/logout"
----display:-"page"-------------------#how-the-authentication-form-will-be-display-to-the-enduser
----scope:-"email-profile-openid-offline_access"-#list-of-the-scope-you-need
----authentication_ttl:-300---------#maximum-age-of-the-authentication
----token_ttl:-300------------------#maximum-age-for-tokenid
----jwk_url:-"https://login.lescommuns.org:8443/auth/realms/master/protocol/openid-connect/certs"-#url-to-the-json-web-key-of-openid-connect-provider
----jwk_cache_ttl:-86400-------------#validity-periods-in-second-where-the-jwk-store-in-cache-is-valid
----enabled_state:-true-------------#enable-the-use-of-the-state-value.-this-is-useful-for-mitigate-replay-attack
----enabled_nonce:-true-------------#enable-the-use-of-the-nonce-value.-this-is-useful-for-mitigate-replay-attack
----enduserinfo_request_method:-"post"-#define-the-method-(post,-get)-used-to-request-the-enduserinfo-endpoint-of-the-oidc-provider
----redirect_after_logout:-"https://sso-synfony.marc.fun"-----------#uri-or-route-name-used-for-redirect-user-after-a-logout

edit-vendor/waldo/openid-connect-relying-party-bundle/waldo/openidconnect/relyingpartybundle/openidconnect/constraint/idtokenvalidator.php-and-comment-$this->errors[]-=-"issuer-are-not-the-same";-because-keycloak-return-"https://login.lescommuns.org:8443/auth/realms/master"-and-the-script-is-comparing-to-the-value-of-the-issuer-in-`config.yml`-wich-is-"https://login.lescommuns.org:8443/auth/realms/master/protocol/openid-connect"

to-show-the-result-of-sso,-edit-vendor/waldo/openid-connect-relying-party-bundle/waldo/openidconnect/relyingpartybundle/openidconnect/resourceowner/abstractgenericoicresourceowner.php-and-after-$oictoken->setrawtokendata($content);-add-:

echo-'<pre>';-print_r($content);-echo-'</pre>';-exit;

the-logout-url-is-<a-href="{{-path('_oic_rp_logout')-}}">logout</a>

--http://blog.keycloak.org/2015/04/running-keycloak-cluster-with-docker.html --http://rhelblog.redhat.com/2016/03/22/red-hat-federation-story-ipsilon-keycloak-a-clash-of-the-titans/ --http://rhelblog.redhat.com/2016/04/26/why-use-sssd-instead-of-a-direct-ldap-configuration-for-applications/ --https://keycloak.gitbooks.io/server-adminstration-guide/content/topics/user-federation/sssd.html --https://keycloak.gitbooks.io/securing-client-applications-guide/content/topics/oidc/javascript-adapter.html --https://github.com/keycloak/keycloak-js-bower --https://keycloak.gitbooks.io/securing-client-applications-guide/content/topics/oidc/nodejs-adapter.html --https://github.com/keycloak/keycloak-nodejs-connect --https://github.com/keycloak/keycloak-nodejs-auth-utils --http://blog.keycloak.org/2015/08/improved-ldap-integration-with-keycloak.html --http://keycloak-user.88327.x6.nabble.com/keycloak-user-create-user-from-keycloak-ui-with-freeipa-backend-td1653.html .html)

You can join us at any moment on the chat.