Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generic OIDC provider support #10152

Merged
merged 6 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
181 changes: 166 additions & 15 deletions docs/developer-guide/integrations/users/openId.md
Original file line number Diff line number Diff line change
@@ -1,39 +1,188 @@
# Integration with OpenID connect

MapStore allows to integrate and login using some common [OpenID connect](https://openid.net/connect/) services. Having this support properly configured, you can make MapStore users able to login with the given OpenID service.
MapStore allows to integrate with [OpenID connect](https://openid.net/connect/) services. This allows to use external services to authenticate users in MapStore. This is useful when you have to integrate MapStore with an existing authentication system, or when you want to use a third-party service to authenticate users.

## Customizing logo an text in Login Form

For details about the configuration for a specific service, please refer to the specific section below. For details about `authenticationProviders` optional values (e.g. to customize icon and/or text to show), refer to the documentation of the [LoginPlugin](https://mapstore.geosolutionsgroup.com/mapstore/docs/api/plugins#plugins.Login).
For details about the configuration for a specific service, please refer to the corresponding section below. If you want to customize the icon and/or text displayed, you can refer to the documentation of the [LoginPlugin](https://mapstore.geosolutionsgroup.com/mapstore/docs/api/plugins#plugins.Login).

By default `authenticationProviders` is `{"type": "basic", "provider": "geostore"}`, that represents the standard login on **MapStore** with username and password. With the default configuration, when the user try to login, MapStore will show the classic login form.
By default, the `authenticationProviders` field contains only `{"type": "basic", "provider": "geostore"}`, which represents the standard login on **MapStore** using a username and password. With this default configuration, when a user tries to log in, MapStore will display the classic login form.

It is possible to add other providers to the list (e.g. `openid`) and they will be added as options to the login window.
You can remove the `geostore` entry from `authenticationProviders` list to remove the login form from the possible login systems.
You can add additional providers to the list (e.g., `openid`), and they will be included as options in the login window. If you want to remove the login form and only use the added providers, you can remove the `geostore` entry from the `authenticationProviders` list.

!!! note
If only one OpenID entry is present in `authenticationProviders` (and no `geostore` entry available), clicking on login in the login menu will not show any intermediate window and you will be redirected directly to the OpenID provider configured. If more than one entry is present in `authenticationProviders` list, the user will have to choose one of them to be authenticated.
!!! info
If only one OpenID entry is present in `authenticationProviders` (and no `geostore` entry available), clicking on the login entry in the login menu will redirect directly to the OpenID provider login page configured, without showing the login window. If more than one entry is present in `authenticationProviders` list, the user will see the login window before to choose one of the services configured to be authenticated.
offtherailz marked this conversation as resolved.
Show resolved Hide resolved

## Supported OpenID services

MapStore allows to integrate with the following OpenID providers.
MapStore provides a generic OpenID connect provider (`oidc`) that can be used to configure any OpenID Connect service (Google, Microsoft, Keycloak, Facebook, Github ...). In addition, MapStore provides specific configurations for some services. This means that you can configure MapStore to use the following services out of the box:
offtherailz marked this conversation as resolved.
Show resolved Hide resolved

- Google
- Keycloak
- OpenID connect
- Google (specific)
- Keycloak (specific)

For each service you want to add you have to:
offtherailz marked this conversation as resolved.
Show resolved Hide resolved

- properly configure the backend
- configure the service (e.g., create a new application on Google Console, create a new client on Keycloak, etc.)
- properly configure the backend (in `mapstore-ovr.properties`)
- modify `localConfig.json` adding a proper entry to the `authenticationProviders`.
offtherailz marked this conversation as resolved.
Show resolved Hide resolved

Morover the keycloak provider allows to configure advanced features like Single Sign On (SSO) with other applications and direct user database integration as well as for ldap.
offtherailz marked this conversation as resolved.
Show resolved Hide resolved

!!! note
For the moment the generic `oidc` provider does not support multiple instances. This means that you can configure only **one** generic `oidc` provider. You can configure the specific providers (e.g., `google`, `keycloak`) in addition to the generic `oidc` provider, but not multiple instances of the generic `oidc` provider. So for instance you can configure a generic `oidc` provider (e.g. connected to Github) plus a `google` and a `keycloak` provider, but not two generic `oidc` providers.

### OpenID connect (generic)

In order to configure the generic OpenID provider with a service of your choice you have to:

- Configure OpenID provider client
offtherailz marked this conversation as resolved.
Show resolved Hide resolved
- onfigure MapStore back-end
offtherailz marked this conversation as resolved.
Show resolved Hide resolved
- Configure MapStore front-end
offtherailz marked this conversation as resolved.
Show resolved Hide resolved

#### Configure OpenID provider client

This step depends on the specific OpenID provider you are using. Please refer to the specific documentation of the OpenID provider you are using. You can find some examples about how to configure a generic OpenID provider with Microsoft Azure in the following sections. The same information are valid for other OpenID providers, like google, keycloak, etc.
offtherailz marked this conversation as resolved.
Show resolved Hide resolved
You have to get the following information:

- **Client ID**: the client id. This is the client id that have to be present on the OpenID provider
offtherailz marked this conversation as resolved.
Show resolved Hide resolved
- **Client Secret**: the client secret. This is the client secret for the client id on the OpenID provider
- **Discovery URL**: the discovery URL. This is the URL that contains all the information for the specific service.

#### Configure MapStore back-end
offtherailz marked this conversation as resolved.
Show resolved Hide resolved

In order to configure the generic OpenID provider you have to:

- create/edit `mapstore-ovr.properties` file (in data-dir or class path) to configure the generic provider this way:

```properties
# enables the keycloak OpenID Connect filter
oidcOAuth2Config.enabled=true

# note: this is the client id have to be present on the OpenID provider
oidcOAuth2Config.clientId=mapstore-server
oidcOAuth2Config.clientSecret=<THE_CLIENT_SECRET>
# the discovery URL
oidcOAuth2Config.discoveryUrl=http://keycloak:8080/auth/realms/mapstore/.well-known/openid-configuration
oidcOAuth2Config.sendClientSecret=true
# create the user if not present
oidcOAuth2Config.autoCreateUser=true
oidcOAuth2Config.redirectUri=http://localhost:8080/mapstore/rest/geostore/openid/oidc/callback
# Internal redirect URI (you can set it to relative path like this `../../..` to make this config work across domain)
oidcOAuth2Config.internalRedirectUri=http://localhost:8080/mapstore
# user name attribute (default is `email`)
# oidcOAuth2Config.principalKey=email
# Optional role claims, if a claim contains roles, you can map them to MapStore roles. (roles can be only ADMIN or USER)
# oidcOAuth2Config.rolesClaim=roles
# Optional group claims, if a claim contains groups, you can map them to MapStore groups.
# oidcOAuth2Config.groupsClaim=groups
offtherailz marked this conversation as resolved.
Show resolved Hide resolved
# Enables global logout from SSO, if properly confugred. false by default
# oidcOAuth2Config.globalLogoutEnabled=true

```

- `oidcOAuth2Config.clientId`: the client id. This is the client id that have to be present on the OpenID provider
offtherailz marked this conversation as resolved.
Show resolved Hide resolved
- `oidcOAuth2Config.clientSecret`: the client secret. This is the client secret for the client id on the OpenID provider
- `oidcOAuth2Config.discoveryUrl`: the discovery URL. This is the URL that contains all the information for the specific service.
- `oidcOAuth2Config.sendClientSecret`: if `true`, the client secret will be sent to the OpenID provider. If `false`, the client secret will not be sent.
- `oidcOAuth2Config.autoCreateUser`: if `true`, the user will be created if not present in the MapStore database. If `false`, the user will not be created ( useful if the user is managed by an external service like Keycloak or LDAP).
offtherailz marked this conversation as resolved.
Show resolved Hide resolved
- `oidcOAuth2Config.redirectUri`: the redirect URI. This is the URI that the OpenID provider, and it must be the effective URI of the MapStore application, with the path `/rest/geostore/openid/oidc/callback`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a missing part here. Please reformulate better.

- `oidcOAuth2Config.internalRedirectUri`: the internal redirect URI. This is the URI that the MapStore will redirect to after the login. It must be the effective URI of the MapStore application.
- `oidcOAuth2Config.principalKey`: (*optional*) the user name attribute. This is the attribute that will be used as the user name. The default is `email`.
offtherailz marked this conversation as resolved.
Show resolved Hide resolved
- `oidcOAuth2Config.rolesClaim`: (*optional*) the role claims. If a claim contains roles, you can map them to MapStore roles. The roles can be only `ADMIN` or `USER`. If the claim is not present, the default role will be `USER`.
- `oidcOAuth2Config.groupsClaim`: (*optional*) the group claims. If a claim contains groups, you can map them to MapStore groups. If the claim is not present, no group will be assigned (except the default `everyone` group).
offtherailz marked this conversation as resolved.
Show resolved Hide resolved
- `oidcOAuth2Config.globalLogoutEnabled`: (*optional*): if true (and the server supports it) invokes global logout on MapStore logout

!!! note
For the moment we can configure only one authentication per service type (only one for google, only one for keycloak ...).
The `rolesClaim` and `groupsClaim` are optional. If you don't need to map roles or groups, you can omit them. At the moment, there is no mapping for roles and groups for the generic OIDC provider. If you need to map roles and groups, you can use the `keycloak` provider.

#### Configure MapStore front-end
offtherailz marked this conversation as resolved.
Show resolved Hide resolved

- Add an entry for `oidc` in `authenticationProviders` inside `localConfig.json` file.

```json
{
"authenticationProviders": [
{
"type": "openID",
"provider": "oidc",
"title": "My custom identity provider"
},
{
"type": "basic",
"provider": "geostore"
}
]
}
```

You can customize the `title` to show in the login form, add an `imageURL` or use only one `authenticationProviders`, removing the `geostore` entry, if you want to use only the OpenID provider. In this case the user will be redirected directly to the OpenID provider without showing the login form.
offtherailz marked this conversation as resolved.
Show resolved Hide resolved

#### Example with Microsoft Azure

Microsoft Azure provides OpenID Connect support. This is an example of how to configure MapStore to use Microsoft Azure as an OpenID provider. The same steps can be applied to other OpenID providers. Please refer to the specific documentation of the OpenID provider you are using. [Here](https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-register-app) the one for Microsoft Azure.

Here a quick summary of the steps to configure Microsoft Azure as an OpenID provider and get the information needed to configure MapStore:

1. Create a new application ![Create azure application](img/azure-1.jpg)
2. Set the proper valid redirect URLs ![set redirect URL](img/azure-2.jpg) to: `https://<your-domain>/mapstore/rest/geostore/openid/oidc/callback`
3. Create and copy client secret ![Create and copy client secret](img/azure-3.jpg)
offtherailz marked this conversation as resolved.
Show resolved Hide resolved
4. Add optional claims if needed ![Add optional claims](img/azure-4.jpg)
5. Copy endpoints and data to configure MapStore ![Copy endpoints](img/azure-5.jpg)

These steps are based on the [Microsoft Azure documentation](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app).
Please refer the official documentation for any detail or additional configuration.

Here also some sample configurations for MapStore (see the following sections for details):
offtherailz marked this conversation as resolved.
Show resolved Hide resolved

`mapstore-ovr.properties`:

```properties
# enables the keycloak OpenID Connect filter
offtherailz marked this conversation as resolved.
Show resolved Hide resolved
oidcOAuth2Config.enabled=true

# note: this is the client id you have created in Keycloak
oidcOAuth2Config.clientId=<CLIENT_ID>
oidcOAuth2Config.clientSecret=<CLIENT_SECRET>

# DISCOVERY_URL something like https://login.microsoftonline.com/abc-dfe-ghi-123-345-567-789/v2.0/.well-known/openid-configuration
oidcOAuth2Config.discoveryUrl=<DISCOVERY_URL>
oidcOAuth2Config.sendClientSecret=true
# create the user if not present
oidcOAuth2Config.autoCreateUser=true
# Here you have to set your redirect URI (here is configured for localhost)
oidcOAuth2Config.redirectUri=http://localhost:8080/mapstore/rest/geostore/openid/oidc/callback
# Internal redirect URI (you can set it to relative path like this `../../..` to make this config work across domain)
oidcOAuth2Config.internalRedirectUri=http://localhost:8080/mapstore
```

`localConfig.json.patch` ( *with a custom title and an image with the Microsoft logo* to show in the login form)

```json
{
"authenticationProviders": [
{
"type": "openID",
"provider": "oidc",
"title": "Microsoft",
"imageURL": "data:image/svg+xml;base64,PHN2ZyBhcmlhLWhpZGRlbj0idHJ1ZSIgdmlld0JveD0iMCAwIDI1IDI1IiBmaWxsPSJub25lIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGl0ZW1wcm9wPSJsb2dvIiBpdGVtc2NvcGU9Iml0ZW1zY29wZSI+CgkJCTxwYXRoIGQ9Ik0xMS41MjE2IDAuNUgwVjExLjkwNjdIMTEuNTIxNlYwLjVaIiBmaWxsPSIjZjI1MDIyIj48L3BhdGg+CgkJCTxwYXRoIGQ9Ik0yNC4yNDE4IDAuNUgxMi43MjAyVjExLjkwNjdIMjQuMjQxOFYwLjVaIiBmaWxsPSIjN2ZiYTAwIj48L3BhdGg+CgkJCTxwYXRoIGQ9Ik0xMS41MjE2IDEzLjA5MzNIMFYyNC41SDExLjUyMTZWMTMuMDkzM1oiIGZpbGw9IiMwMGE0ZWYiPjwvcGF0aD4KCQkJPHBhdGggZD0iTTI0LjI0MTggMTMuMDkzM0gxMi43MjAyVjI0LjVIMjQuMjQxOFYxMy4wOTMzWiIgZmlsbD0iI2ZmYjkwMCI+PC9wYXRoPgoJCTwvc3ZnPgo="
},
{
"type": "basic",
"provider": "geostore"
}
]

}
```

### Google

The Google OpenID Connect provider allows to use Google as an authentication provider. This is useful when you want to use Google as an authentication provider for your application.

#### Create Oauth 2.0 credentials on Google Console

In order to setup the openID connection you have to setup a project in Google API Console to obtain Oauth 2.0 credentials and configure them.
In order to setup the openID connection you have to setup a project in Google API Console to obtain Oauth 2.0 credentials and configure them. Here a quick summary of the steps to configure Google as an OpenID provider. For more details, please refer to the [Google documentation](https://developers.google.com/identity/openid-connect/openid-connect).

- Open Google developer console and, from credentials section, create a new credential of type **Oauth client ID**
offtherailz marked this conversation as resolved.
Show resolved Hide resolved

Expand All @@ -51,7 +200,9 @@ Please follow the [Google documentation](https://developers.google.com/identity/

After the setup, you will have to:

- create/edit `mapstore-ovr.properties` file (in data-dir or class path) to configure the google provider this way:
- create/edit `mapstore-ovr.properties` file (in data-dir or class path) to configure the google OpenID integration by inserting in particular the `clientId` and `clientSecret` obtained from Google Console. You have also set the `autoCreateUser` to `true` to create the user if not present in the MapStore database:
offtherailz marked this conversation as resolved.
Show resolved Hide resolved

Here an example of the configuration, documented inline:

```properties

Expand All @@ -65,7 +216,7 @@ googleOAuth2Config.clientSecret=<the_client_secret_from_google_dev_console>
# create the user if not present
googleOAuth2Config.autoCreateUser=true

# Redirect URL
# Redirect URL (needs to be configured in the Google Console too)
googleOAuth2Config.redirectUri=https://<your-appliction-domain>/mapstore/rest/geostore/openid/google/callback
# Internal redirect URI (you can set it to relative path like this `../../..` to make this config work across domain)
googleOAuth2Config.internalRedirectUri=https://<your-appliction-domain>/mapstore/
Expand Down
30 changes: 29 additions & 1 deletion docs/developer-guide/mapstore-migration-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,34 @@ This is a list of things to check if you want to update from a previous version
- Optionally check also accessory files like `.eslinrc`, if you want to keep aligned with lint standards.
- Follow the instructions below, in order, from your version to the one you want to update to.

## Migration from 2024.01.00 to 2024.02.00

### Integration with openID Connect

A generic OpenID Connect (OIDC) authentication support has been introduced in MapStore. This feature allows to authenticate users using an OIDC provider, like Keycloak, Okta, Google, Azure, etc.

In order to have this feature working, you need to update in your project the `geostore-spring-security.xml` file in your project, if it has been customized and you are not using the default one.
offtherailz marked this conversation as resolved.
Show resolved Hide resolved
If you are using the default one, you can skip this step.

Here the changes to apply if needed:

```diff
@@ -24,6 +24,7 @@
<security:custom-filter ref="sessionTokenProcessingFilter" after="FORM_LOGIN_FILTER"/>
<security:custom-filter ref="keycloakFilter" before="BASIC_AUTH_FILTER"/>
<security:custom-filter ref="googleOpenIdFilter" after="BASIC_AUTH_FILTER"/>
+ <security:custom-filter ref="oidcOpenIdFilter" before="OPENID_FILTER"/> <!-- ADD a filter with this ref -->
<security:anonymous />
</security:http>

@@ -52,6 +53,7 @@

<!-- OAuth2 beans -->
<context:annotation-config/>
+ <bean id="oidcSecurityConfiguration" class="it.geosolutions.geostore.services.rest.security.oauth2.openid_connect.OpenIdConnectSecurityConfiguration"/> <!-- add this bean to configure the integration -->

<bean id="googleSecurityConfiguration" class="it.geosolutions.geostore.services.rest.security.oauth2.google.OAuthGoogleSecurityConfiguration"/>

offtherailz marked this conversation as resolved.
Show resolved Hide resolved
## Migration from 2023.02.02 to 2024.01.00

### TOC plugin refactor
Expand All @@ -33,7 +61,7 @@ The table of content (TOC) has been refactored with following changes:
- `activateQueryTool` removed property, now the button will be directly added by `FilterLayer` plugin, when available
- `activateDownloadTool` removed property, now the button will be added directly from `LayerDownload` when available
- `activateMetedataTool` removed property, now the button will be added directly from `MetadataInfo` when availables
- `checkPlugins` remove property, now availability of tools rely on the related plugin so this check is not needed anymore
- `checkPlugins` remove property, now availability of tools rely on the related plugin so this check is not needed anymore
- `showFullTitleOnExpand` removed property, the new style allows for seeing the full title inline without duplicating it
- `metadataTemplate` this configuration has been moved to `MetadataInfo` plugin
- `metadataOptions` this configuration has been moved to `MetadataInfo` plugin
Expand Down
7 changes: 6 additions & 1 deletion product/config/db/geostore-spring-security-db.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<security:custom-filter ref="sessionTokenProcessingFilter" after="FORM_LOGIN_FILTER"/>
<security:custom-filter ref="keycloakFilter" before="BASIC_AUTH_FILTER"/>
<security:custom-filter ref="googleOpenIdFilter" after="BASIC_AUTH_FILTER"/>
<security:custom-filter ref="oidcOpenIdFilter" before="OPENID_FILTER"/>
<security:anonymous />
</security:http>

Expand All @@ -50,9 +51,13 @@
<bean id="preauthenticatedAuthenticationProvider" class="it.geosolutions.geostore.services.rest.security.PreAuthenticatedAuthenticationProvider">
</bean>

<!-- OAuth2 beans -->
<context:annotation-config/>
<!-- OAuth2 beans -->

<!-- Generic OIDC -->
<bean id="oidcSecurityConfiguration" class="it.geosolutions.geostore.services.rest.security.oauth2.openid_connect.OpenIdConnectSecurityConfiguration"/>

<!-- Google -->
<bean id="googleSecurityConfiguration" class="it.geosolutions.geostore.services.rest.security.oauth2.google.OAuthGoogleSecurityConfiguration"/>

<!-- Keycloak -->
Expand Down