diff --git a/README.md b/README.md
index 0b66a85..9c650be 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,8 @@ The purpose of this module is to support the
[WS-FED protocol](http://docs.oasis-open.org/wsfed/federation/v1.2/os/ws-federation-1.2-spec-os.html)
in [Keycloak](https://www.keycloak.org/). Only Web (Passive) requestors are supported, as defined in
[section 13 of the specification](http://docs.oasis-open.org/wsfed/federation/v1.2/os/ws-federation-1.2-spec-os.html#_Toc223175002).
-However, in this capacity the WS-Fed protocol can be used for communication with:
+It should be noted that the optional elements of the protocol (attribute services and pseudonym services) are not
+currently supported. However, in its current capacity the WS-Fed protocol can be used for communication with:
* Keycloak clients (WS Resources), with Keycloak acting as an IdP/STS.
* Other IdPs, with Keycloak acting as an Identity Broker.
@@ -46,6 +47,7 @@ layers=keycloak,wsfed
__standalone.xml__
```xml
+...
auth
module:com.quest.keycloak-wsfed
@@ -70,14 +72,224 @@ clients, then restart keycloak.
### How to setup a Keycloak client
-### How to setup a Keycloak identity broker.
+In this section we will explain how to setup a keycloak client. We will use two types of servers to act as WS-Fed
+Resources (Service Providers) for our example: The first is an
+[IdP test client](https://github.com/cloudtrust/idp-test-client), while the second is Sharepoint 2013.
+
+#### Creating a client
+
+A WS-Fed client is added as any other: go to the **Clients** menu item and create a new client, making sure that in the
+"Add Client" screen, the **client protocol**, is `wsfed`. Normally, any value can be used for the **Client ID**, as long
+as it is shared with the WS-Fed resource.
+
+A small side note: in WS-Fed parlance, the actual term for **Client ID** is _Realm_, and is the value shared in the
+`wtrealm` uri query. This can obviously lead to confusion when working with keycloak.
+
+##### Settings tab
+
+The values **Name**, **Description**, **Enabled**, **Consent required** and **Client template** are the same general
+parameters for clients as described in the
+[Keycloak documentation for SAML clients](https://www.keycloak.org/docs/latest/server_admin/index.html#saml-clients).
+
+The following set of options are protocol specific: The option **Send JWT instead of SAML** determines if a JWT token
+or SAML is used. If a JWT token is used, the option **Include x5t in header** is available. If a SAML token is used, the
+**SAML Assertion Token Format** option allows the use of `SAML 1.1` or `SAML 2.0` tokens. The **Front Channel Logout**
+option determines if the logout requires a browser redirect to the client (for `true`) or if the server performs a
+background invocation (for`false`).
+
+The last set of options concern the URIs of the client. The values **Root URL**, **Valid Redirect URIs** and **Base
+URL** are the same as those described in the
+[Keycloak documentation for SAML clients](https://www.keycloak.org/docs/latest/server_admin/index.html#saml-clients).
+
+##### Mappers tab
+
+Mappers are generally handled in the same way as described as described in the
+[keycloak documentation on mappers](https://www.keycloak.org/docs/latest/server_admin/index.html#_protocol-mappers). The
+difference is that there are two sets of mappers, **SAML mappers** and **OIDC mappers**. **SAML mappers** should be used
+if a SAML token is used, and OIDC mappers should be used if a **JWT token** is used. Doing the contrary will not cause
+an error, but the mapper will be ignored.
+
+Mappers are equivalent to those from the SAML and OIDC clients, however, there is an extra mapper present
+in the WS-Fed SAML mappers: a `SAML javascript mapper`. It's use is almost analog to the OIDC script mapper:
+the [nashorn javascript engine](https://docs.oracle.com/javase/10/nashorn/introduction.htm#JSNUG136) is used to
+evaluate the input script, and the last statement is the value that will be returned in the SAML attribute. The
+sole difference to the OIDC varient is that the `SAML javascript mapper` can handle Iterables or arrays as a return
+value: the result will either be multiple attributes, or a single attribute with a grouped value, depending on the
+value of the **Single Group Attribute** option.
+
+##### Installation tab
+
+The installation tab gives access to the WS-Fed metadata, which can be used to configure the WS-Fed resource. This
+information can also be accessed at `http[s]://:/auth/realms//protocol/wsfed/descriptor`.
+
+#### Example: configuration with the IdP test client
+
+For this example we will be running keycloak with the WS-Fed module installed on localhost:8080 and the
+[IdPTestClient](https://github.com/cloudtrust/idp-test-client) on localhost:7000.
+
+##### Realm setup
+
+Create a realm `TestRealm`, with the roles `user`, `testUser` and `groupUser` in addition to keycloak's default roles.
+In this realm, create a user with the following characteristics:
+
+* **Username**: `test.testuser`
+* **Email**: `test.testuser@testrealm.io`
+* **Firstname**: `test`
+* **Lastname**: `testuser`
+* **User Enabled**: `on`
+* **Email Verified**: `off`
+
+In **credentials**, set the password to `password` (with **Temporary** set to `off`). In **Role Mappings**, and the roles
+`user` and `testUser`.
+
+##### Client setup
+
+Go to the **Clients** menu, and create a new client. In the "Add Client" page screen choose `wsfed` for the
+**client protocol**, `WSFedTestClient` for the **Client ID** and save.
+
+In the **Settings** tab, set the **Valid Redirect URIs** to `http://localhost:7000/*`, leave the rest of the values
+unchanged and save.
+
+In the **Mappers** tab, create a new mapper. For **Mapper Type** select `SAML Role list`, and then set the **Name** to
+`SAML Role mapper` and the **SAML Attribute Nameformat** to `Basic` before saving.
+
+Go to the **Installation** tab, and select `WSFed Metadata IDP Descriptor`, the values will be useful for the next step.
+
+##### IdPTestClient setup
+
+Clone the [idp-test-client](https://github.com/cloudtrust/idp-test-client) repository, and follow the instructions to
+build the jar.
+
+Create a new certif.cer file. The format of the file should be the following:
+
+```
+-----BEGIN CERTIFICATE-----
+CERTIFICATE_VALUE
+-----END CERTIFICATE-----
+```
+
+With `CERTIFICATE_VALUE` being the value from the "X509Certificate" field from the `WSFed Metadata IDP Descriptor`.
+
+Create a keystore with the command:
+
+```
+keytool -importcert -file certif.cer -keystore localstore.jks -alias "TestRealm"
+```
+
+And choose `localpass` as the password (make sure that the java keytool is on the PATH).
+
+Create the following `fediz-config.xml` file for the ws-fed configuration of the IdPTestClient:
+
+```xml
+
+
+
+
+ http://localhost:7000/
+
+
+
+
+
+
+
+
+
+
+ http://localhost:8080/auth/realms/TestRealm/protocol/wsfed
+ WSFedTestClient
+ /j_spring_fediz_security_check
+
+ /wsfedLogout
+ /performLogout
+
+
+```
+
+Note that the "issuer" is the value in "EndpointReference" from the `WSFed Metadata IDP Descriptor`.
+
+Then, making sure that the jar and the fediz-config.xml are in a same directory, run:
+
+```
+java -jar IdPTestClient.jar --fediz.configFilePath=fediz_config.xml
+```
+
+The website at localhost:7000 will have the option to login with WS-Fed.
+
+#### Example: configuration in Sharepoint 2013
+
+The realm setup for this example is the same as the one for the IdPTestClient setup.
+
+Go to the **Clients** menu, and create a new client. In the "Add Client" page screen choose `wsfed` for the
+**client protocol**. For Sharepoint, the **Client ID** must be in the urn format, so we will have
+`urn:testsharepoint:wsfed` (with an incorrect format, Sharepoint will throw an Unknown SPRequest error). Save the
+values.
+
+Sharepoint will only accept https connections (this is also true for the keycloak endpoint), and SAML 1.1 tokens.
+Imagining that Sharepoint is also on the localhost, we have the following values in the **Settings** tab:
+
+* **SAML Assertion Token Format**: `SAML1.1`
+* **Valid Redirect URIs**: `https://localhost/*`
+
+In the **Mappers** tab create the following mappers:
+
+1. **Name**: `SAML role list`, **Mapper Type**: `SAML Role List`, **Role attribute name**: `Role`, **SAML Attribute
+NameFormat**: `Basic`
+2. **Name**: `SAML upn`, **Mapper Type**: `SAML User Property`, **Property**: `username`, **SAML Attribute Name**:
+`upn`, **SAML Attribute NameFormat**: `Basic`
+3. **Name**: `SAML email`, **Mapper Type**: `SAML User Property`, **Property**: `email`, **SAML Attribute Name**:
+`emailaddress`, **SAML Attribute NameFormat**: `Basic`
+
+In the **Installation** tab, copy the content of the "X509Certificate" field from the `WSFed Metadata IDP Descriptor` to
+a new certif.cer file.
+
+Next is setting up Sharepoint to use the Keycloak server. The following
+[guide to configure ADFS with Sharepoint](https://sharepointobservations.wordpress.com/2013/08/19/sharepoint-2013-how-to-install-and-configure-adfs-2-0/)
+describes the steps from the **Configure SharePoint Web Application** section with pictures. The basic steps are the
+following:
+
+**_Step 1_**: Run the following powershell script as administrator from the SharePoint 2013 Management Shell:
+
+```powershell
+$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("Path\To\certif.cer")
+
+### This section should only be necessary for self-signed certificates ###
+ $tokenSigningCertificateName = "Keycloak Cloudtrust TestRealm"
+ if (Get-SPTrustedRootAuthority -Identity $tokenSigningCertificateName -ea "silentlycontinue") {
+ Write-Host "Signing certificate already trusted."
+ }
+ else {
+ Write-Host "Adding signing certificate to SharePoint trusts."
+ New-SPTrustedRootAuthority -Name $tokenSigningCertificateName -Certificate $cert
+ }
+### end section ###
+
+ $idClaim = New-SPClaimTypeMapping -IncomingClaimType "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" -IncomingClaimTypeDisplayName "Email address" -SameAsIncoming
+ $map1 = New-SPClaimTypeMapping -IncomingClaimType "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn" -IncomingClaimTypeDisplayName "UPN" -SameAsIncoming
+ $map2 = New-SPClaimTypeMapping -IncomingClaimType "http://schemas.microsoft.com/ws/2008/06/identity/claims/role" -IncomingClaimTypeDisplayName "Role" -SameAsIncoming
+
+ $realm = "urn:testsharepoint:wsfed"
+ $signinurl = "https://localhost:8443/auth/realms/TestRealm/protocol/wsfed"
+ $ap = New-SPTrustedIdentityTokenIssuer -Name "KeycloakTestRealm" -Description "Trust to Keycloak" -Realm $realm -ImportTrustCertificate $cert -ClaimsMappings $map1, $map2, $idClaim -SignInUrl $signinurl -IdentifierClaim $idClaim.InputClaimType
+ $ap.UseWReplyParameter = $true
+ $ap.Update()
+```
+
+Note that the `$signinurl` is the value in "EndpointReference" from the `WSFed Metadata IDP Descriptor`.
+
+**_Step 2_**: With Sharepoint 2013 Central Administration, go to **Manage Web Applications** > **Sharepoint - localhost:443** >
+**Authentication Providers** > **default**, and under "Trusted Identity provider" select `KeycloakTestRealm`.
+
+When going to your Sharepoint at https://localhost, you will now have the option to log in with `KeycloakTestRealm`
+
+### How to setup a Keycloak identity broker
We will explain here how to setup identity brokering using two instances of keycloak: one as identity broker, and the
second as external IdP. Naturally, for this to work, the WS-Fed module must be installed on both instances of Keycloak.
#### Setting up the identity broker
-Go to the `Identity Providers` menu item and create a new identity provider selecting `WS-Fed` from the list.
+Go to the **Identity Providers** menu item and create a new identity provider selecting `WS-Fed` from the list.
The first part of the settings are the general IdP settings, described in the
[keycloak documentation](https://www.keycloak.org/docs/latest/server_admin/index.html#_general-idp-config). The only
@@ -99,7 +311,7 @@ This will give the following information:
* **Single Sign-On Service URL** (in the `PassiveRequestorEndpoint` section)
* **Single Logout Service URL** (in the `PassiveRequestorEndpoint` section, the same as the Single Sign-On Service URL)
- * **Validating X509 Certificates** (in the `X509Certificate` tags). This is only use if the **Validate Signature**
+ * **Validating X509 Certificates** (in the `X509Certificate` tags). This is only used if the **Validate Signature**
option is set to on (which is recommended).
The remaining options are:
@@ -120,7 +332,6 @@ In the `Settings` tab, the only important elements to set are:
* the **SAML Assertion Token Format**, which specifies the type of token to use. Currently only SAML 1.1 and 2.0 tokens
are supported.
-WS-Fed identity brokers.
* the **Valid Redirect URIs** parameter. For a Keyclock identity broker, this value MUST be set to the value of the
**Redirect URI** in the settings tab.
@@ -141,7 +352,7 @@ To get the information, the following mappers must be created in the client:
**SAML Attribute Name** MUST be set to `name`.
* A mapper for the email: Should be of type `SAML User Property`. The **property** should be set to `email`. The
**SAML Attribute Name** MUST be set to `emailaddress`.
-* A mapper for the first name: Should be of type `SAML User Property`. The **property** should be set to `firstName`. The
-**SAML Attribute Name** MUST be set to `givenname`.
+* A mapper for the first name: Should be of type `SAML User Property`. The **property** should be set to `firstName`.
+The **SAML Attribute Name** MUST be set to `givenname`.
* A mapper for the last name: Should be of type `SAML User Property`. The **property** should be set to `lastName`. The
**SAML Attribute Name** MUST be set to `surname`.
\ No newline at end of file
diff --git a/src/main/java/com/quest/keycloak/protocol/wsfed/WSFedLoginProtocolFactory.java b/src/main/java/com/quest/keycloak/protocol/wsfed/WSFedLoginProtocolFactory.java
index 2517864..9d8f887 100644
--- a/src/main/java/com/quest/keycloak/protocol/wsfed/WSFedLoginProtocolFactory.java
+++ b/src/main/java/com/quest/keycloak/protocol/wsfed/WSFedLoginProtocolFactory.java
@@ -101,35 +101,30 @@ public List getDefaultBuiltinMappers() {
true, UPN_CONSENT_TEXT,
true, true);
builtins.add(model);
- defaultBuiltins.add(model);
model = OIDCUserPropertyMapper.createClaimMapper(USERNAME,
"username",
"preferred_username", "String",
true, USERNAME_CONSENT_TEXT,
true, true);
builtins.add(model);
- defaultBuiltins.add(model);
model = OIDCUserPropertyMapper.createClaimMapper(EMAIL,
"email",
"email", "String",
true, EMAIL_CONSENT_TEXT,
true, true);
builtins.add(model);
- defaultBuiltins.add(model);
model = OIDCUserPropertyMapper.createClaimMapper(GIVEN_NAME,
"firstName",
"given_name", "String",
true, GIVEN_NAME_CONSENT_TEXT,
true, true);
builtins.add(model);
- defaultBuiltins.add(model);
model = OIDCUserPropertyMapper.createClaimMapper(FAMILY_NAME,
"lastName",
"family_name", "String",
true, FAMILY_NAME_CONSENT_TEXT,
true, true);
builtins.add(model);
- defaultBuiltins.add(model);
model = OIDCUserPropertyMapper.createClaimMapper(EMAIL_VERIFIED,
"emailVerified",
"email_verified", "boolean",
@@ -139,7 +134,6 @@ public List getDefaultBuiltinMappers() {
model = OIDCFullNameMapper.create(FULL_NAME, true, FULL_NAME_CONSENT_TEXT, true, true);
builtins.add(model);
- defaultBuiltins.add(model);
ProtocolMapperModel address = AddressMapper.createAddressMapper();
builtins.add(address);
@@ -168,7 +162,6 @@ public List getDefaultBuiltinMappers() {
builtins.add(model);
model = SAMLRoleListMapper.create("saml role list", "Role", AttributeStatementHelper.BASIC, null, false);
builtins.add(model);
- defaultBuiltins.add(model);
}
diff --git a/src/main/resources/theme/wsfed/admin/resources/partials/client-detail.html b/src/main/resources/theme/wsfed/admin/resources/partials/client-detail.html
index 131908b..b5d566b 100644
--- a/src/main/resources/theme/wsfed/admin/resources/partials/client-detail.html
+++ b/src/main/resources/theme/wsfed/admin/resources/partials/client-detail.html
@@ -305,7 +305,7 @@
{{:: 'base-url.tooltip' | translate}}
-