Skip to content

Commit

Permalink
Add documentation for the Keycloak (#354)
Browse files Browse the repository at this point in the history
* Also adjust heading levels in Troubleshooting,
* and document the "NameIDPolicy Format" field
  • Loading branch information
duemir authored Jul 4, 2023
1 parent adcc470 commit 6935543
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 14 deletions.
5 changes: 5 additions & 0 deletions doc/CONFIGURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ you also could set the sessions on Jenkins to be shorter than those on your IdP.
rather than its default. Check with the IdP administrators to find out which authentication contexts are available
* **SP Entity ID** - If this field is not empty, it overrides the default Entity ID for this Service Provider.
Service Provider Entity IDs are usually a URL, like ***http://jenkins.example.org/securityRealm/finishLogin***.
* **NameIDPolicy Format** - Set your NameIDPolicy in the AuthnRequest, for example: `urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified`
* **Use cache for configuration files** - The SP metadata is written on every login, enable this setting change the behaviour to use cache, and save the file only if it has changes.
* **Use Random relayState value** - When you enable this option the value of the relayState parameter sent to the IdP is a random generated value. The default value of relayState is `JENKINS_URL/securityRealm/finishLogin`
* **Encryption** - If your provider requires encryption or signing, you can specify the keystore details here that should be used.
Expand Down Expand Up @@ -120,6 +121,10 @@ see [their docs on the SAML connector](https://onelogin.service-now.com/support?

[Configure Azure](CONFIGURE_AZURE.md)

### Keycloak

[Configure Keycloak](CONFIGURE_KEYCLOAK.md)

### Configuring Single Log Out

When using a proxy like Apache, it is possible to catch the logout with a **mod_rewrite** and redirect the browser to the Identity Provider for Single Log Out.
Expand Down
51 changes: 51 additions & 0 deletions doc/CONFIGURE_KEYCLOAK.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Configure Keycloak

*Note:* replace https://keycloak.example.com with the root URL of your Keycloak service, replace jenkins.example.com with the name of your Jenkins host.

## Retrieve Jenkins Service Provider metadata

1. Choose SAML 2.0 as a Security Realm
2. Set the `IdP Metadata URL` to `https://keycloak.example.com/realms/{realm}/protocol/saml/descriptor`, where `{realm}` is the Realm of your client
3. Set the `Refresh Period` to `1440` (24h, suggested value)
4. Click `Validate IdP Metadata` to make sure metadata can be fetched
5. Click `Apply`
6. Find `Service Provider Metadata` link and save it as an XML file, e.g., `jenkins-sp-metadata.xml`

## Import a new client into Keycloak realm

[Using an entity descriptor to create a client](https://www.keycloak.org/docs/latest/server_admin/index.html#proc-using-an-entity-descriptors_server_administration_guide) is the reference documentation.

In a different tab in the Keycloak admin interface:

1. On the `Clients` page of the same realm as above chose to `Import client`
2. Select above `jenkins-sp-metadata.xml` as your `Resource file`
3. (Optional) Give a meaningful Name and Description
4. Save
5. Find "Name ID format" field and change to `username` or `persistent`
6. Save your change

## Add predefined mappers with user details

In the client details of the newly imported client:

1. Switch to `Client scopes`
2. Open a `dedicated` client scope
3. `Add predefined mappers`
4. Choose `X500 email`, `X500 givenName`, `X500 surname` and click `Add`
5. Open the newly added `X500 email` mapper and note the `SAML Attribute Name`, e.g., `urn:oid:1.2.840.113549.1.9.1`
6. Repeat previous step for given name or surname depending on your preference of Display Name on the jenkins side, e.g., `urn:oid:2.5.4.42` for given name.
7. For the sake of an example we will use a predefined `Role list` mapper as a source of groups (`SAML Attribute Name` is `Role`). However, depending on your use case one more mapper might be needed to share group membership with Jenkins.

## Complete SAML 2.0 Security Realm configuration

Back on the Jenkins Security page:

1. Set "Email Attribute" to the value noted in step 5 above
2. Set "Display Name Attribute" to the value noted in step 6 above
3. Set "Group Attribute" to the value noted in step 7 above
4. "Save"

Test the authentication in an Incognito Window or a different browser.

For more details about the SAML Plugin configuration take a look at [Configuration Guide](CONFIGURE.md)
For troubleshooting steps and know issue see [Troubleshooting](TROUBLESHOOTING.md)
54 changes: 40 additions & 14 deletions doc/TROUBLESHOOTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ When you face an issue you could try to enable a logger to these two packages on
* org.pac4j - FINE

**If you have configured the Jenkins proxy setting, and you do not want to use the proxy to connect to your IdP you have to add your IdP to no-proxy hosts**


## Examples SAML XML documents

### IdP Metadata

The IdP metadata should look like this one, the main data are the `entityID`, `IDPSSODescriptor` section, and `SingleSignOnService` the three sections are needed.
Expand Down Expand Up @@ -110,7 +112,7 @@ This is an example of SAMLResponse, it is the message sent by the IdP to Jenkins
</Response>
```

### SAMLException: Identity provider has no single sign on service available for the selected
## SAMLException: Identity provider has no single sign on service available for the selected

You have to check your IdP metadata contains the section `SingleSignOnService`

Expand All @@ -119,7 +121,7 @@ org.pac4j.saml.exceptions.SAMLException: Identity provider has no single sign on
at org.pac4j.saml.context.SAML2MessageContext.getIDPSingleSignOnService(SAML2MessageContext.java:93)
```

### Azure AD
## Azure AD

After leaving the system for some period of time (like overnight) and trying to log in again you get this error

Expand Down Expand Up @@ -157,7 +159,7 @@ at java.lang.Thread.run(Thread.java:748)
* Enable the advanced "force authentication" setting is another workaround.


### Identity provider has no single sign on service available for the selected...
## Identity provider has no single sign on service available for the selected...

* Check the SP EntryID configured on the IdP
* Check the binding methods supported on your IdP
Expand All @@ -182,7 +184,7 @@ org.pac4j.saml.exceptions.SAMLException: Identity provider has no single sign on
at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:715)
```

### Identity provider does not support encryption settings
## Identity provider does not support encryption settings

* Check the encryption methods, signing methods, and keys types supported by your IdP and set the encryption settings correctly
* Downgrade to 0.14 version, if it works, then enable encryption on that version to be sure that this is the issue
Expand Down Expand Up @@ -211,7 +213,7 @@ Caused by: java.lang.IllegalArgumentException: Illegal base64 character d
at org.jenkinsci.plugins.saml.SamlSecurityRealm.doFinishLogin(SamlSecurityRealm.java:258)
```

### The SAMLResponse is not correct base64 encode
## The SAMLResponse is not correct base64 encode

The SAMLResponse message is not valid because the `SAMLResponse` value is not in Base64 format, or it is corrupted.

Expand All @@ -226,7 +228,7 @@ Caused by: java.lang.IllegalStateException: org.pac4j.saml.exceptions.SAMLExcept
... 77 more
```

### There is no SAMLResponse parameter in the POST message
## There is no SAMLResponse parameter in the POST message

The response message should have a parameter named `SAMLResponse` that should be the XML of the SAMLResponse in Base64 format.

Expand All @@ -239,7 +241,7 @@ Caused by: org.opensaml.messaging.decoder.MessageDecodingException: Request did
... 87 more
```

### No valid subject assertion found in response
## No valid subject assertion found in response

Check that the `SP Entry ID` it is the same in the SP (Jenkins) and IdP, by default Jenkins uses `JENKINS_URL/securityRealm/finishLogin` you can change this value if you use the SAML Plugin's Advanced Setting named "SP Entity ID".

Expand Down Expand Up @@ -272,7 +274,7 @@ at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:62
at java.lang.Thread.run(Thread.java:748)
```

### Authentication issue instant is too old or in the future
## Authentication issue instant is too old or in the future

You should check that your `Maximum Authentication Lifetime` setting is the same that your Idp has, if Jenkins has a lower value you will see this error. The solution is to set `Maximum Authentication Lifetime` to your token validity. Another workaround is to set `Advanced Configuration/Force Authentication` but this will ask for login everytime the session expires.

Expand Down Expand Up @@ -308,7 +310,7 @@ SEVERE: Current assertion validation failed, continue with the next oneorg.pac4j
at java.lang.Thread.run(Thread.java:748)
```

### Unable to create/read keystore
## Unable to create/read keystore

The key store is needed by the pac4j library even do you do not use encryption,
because of that the plugin manages a dummy keystore, it is created and the key is maintained in case it expired.
Expand Down Expand Up @@ -354,7 +356,7 @@ rm $JENKINS_HOME/saml-jenkins-keystore.jks
rm $JENKINS_HOME/saml-jenkins-keystore.xml
```

### Intended destination ${URL} doesn't match any of the endpoint URLs on endpoint
## Intended destination ${URL} doesn't match any of the endpoint URLs on endpoint

```
2019-11-27 16:55:46.826+0000 [id=4549] WARNING o.j.p.saml.SamlSecurityRealm#doFinishLogin: Unable to validate the SAML Response: org.pac4j.saml.exceptions.SAMLException: Intended destination https://JENKINS_SERVER/securityRealm/finishLogin doesn't match any of the endpoint URLs on endpoint http://JENKINS_SERVER/securityRealm/finishLogin; nested exception is org.pac4j.saml.exceptions.SAMLException: org.pac4j.saml.exceptions.SAMLException: Intended destination https://JENKINS_SERVER/securityRealm/finishLogin doesn't match any of the endpoint URLs on endpoint http://JENKINS_SERVER/securityRealm/finishLogin
Expand Down Expand Up @@ -399,18 +401,42 @@ and Jenkins Core uses an old one.
So the only solution is to stop using pac4j library,
and use OpenSAML library directly, but this is a reimplementation of the plugin.

# After an update the authentication fails
## After an update the authentication fails

The first thing to check after and update in case of error it is if the Service provider metadata has changed,
this metadata is available at the URL `JENKINS_URL/securityRealm/metadata`, or in the file `JENKINS_HOME/saml-sp-metadata.xml`
If you IdP support to grab the metadata from an URL is recommended to use the metadata from the URL `JENKINS_URL/securityRealm/metadata`

# After login a `HTTP ERROR 403 No valid crumb was included in the request` error happens
## After login a `HTTP ERROR 403 No valid crumb was included in the request` error happens

This is a configuration error, SAML plugin cannot return a ‘invalid breadcrumb’ error in a login process
if the SP and IdP are correctly configured.
It happens because the redirection to ***https://jenkins.example.com/securityRealm/finishLogin*** is redirected to another URL in Jenkins.
The error usually is related to the Jenkins URL configured, or a reverse proxy configured in front Jenkins that require a valid crumb.
Put the log in verbose mode and check the login process, check that the URLs you are redirected are correct.
See[Troubleshooting Guide](https://github.com/jenkinsci/saml-plugin/blob/main/doc/TROUBLESHOOTING.md#troubleshooting)
and [Configure your IdP](https://github.com/jenkinsci/saml-plugin/blob/main/doc/CONFIGURE.md#configuring-identity-provider-idp)
and [Configure your IdP](https://github.com/jenkinsci/saml-plugin/blob/main/doc/CONFIGURE.md#configuring-identity-provider-idp)

## Authentication fails. Logs show `Response is not success ; actual urn:oasis:names:tc:SAML:2.0:status:Responder`

Example of the full log message

```
2023-01-01 00:00:00.000+0000 [id=12345] WARNING o.j.p.saml.SamlSecurityRealm#doFinishLogin: Unable to validate the SAML Response: Response is not success ; actual urn:oasis:names:tc:SAML:2.0:status:Responder
```

There are likely to be more details regarding the status in the SAML Response. Configure log recorder as described above, reproduce the issue, and look for `SAMLResponse` as shown in example below. Contents of the `<Status>` tag should give a clue.

### `Responder` status from Keycloak

You are using the Keycloak and after inspecting the `SAMLResponse` for the cause of `Responder` status you see:

```xml
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Responder">
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy"/>
</samlp:StatusCode>
</samlp:Status>
```

If you do not explicitly specify the `NameIDPolicy Format` on the Jenkins side and your Keycloak's Client's `Name ID format` is `email`, any user who does not have Email configured will fail to authenticated with the above status.

0 comments on commit 6935543

Please sign in to comment.