Authentication mode
By default the catalog uses the internal database for user management and authentication. However there are some other authentication mechanisms available:
- Configuring LDAP
- Configuring LDAP - Hierarchy
- Configuring CAS
- Configuring OAUTH2 OpenID Connect
- Configuring Keycloak
- Configuring Shibboleth
Which mode to use is configured in WEB-INF/config-security/config-security.xml
or via an environment variable geonetwork.security.type
.
Uncomment the relevant line in WEB-INF/config-security/config-security.xml
:
Configuring LDAP
Lightweight Directory Access Protocol (LDAP) enables GeoNetwork to verify usernames and passwords to a remote identity store. LDAP implementation uses the default GeoNetwork Login User Interface elements.
GeoNetwork currently has 2 approaches to configure LDAP. Verify also the alternative approach in Configuring LDAP - Hierarchy.
The LDAP configuration is defined in WEB-INF/config-security/config-security.properties
, you can then configure your environment updating the previous file or overriding the properties in the file WEB-INF/config-security/config-security-overrides.properties
.
-
Define the LDAP connection:
ldap.base.provider.url
: This tells the portal where the LDAP server is located. Make sure that the computer with the catalog can hit the computer with the LDAP server. Check to make sure that the appropriate ports are opened, etc.ldap.base.dn
: this will usually look something like: "dc=[organizationnamehere],dc=org"ldap.security.principal
/ldap.security.credentials
: Define LDAP administrator user to use to bind to LDAP. If not define, an anonymous bind is made. Principal is the username and credentials property the password.
# LDAP security properties ldap.base.provider.url=ldap://localhost:389 ldap.base.dn=dc=fao,dc=org ldap.security.principal=cn=admin,dc=fao,dc=org ldap.security.credentials=ldap
To verify that you have the correct settings, try to connect to the LDAP server using an LDAP browser application.
-
Define where to find users in LDAP structure for authentication:
ldap.base.search.base
: this is where the catalog will look for users for authentication.ldap.base.dn.pattern
: this is the distinguished name for the user to bind with.{0}
is replaced by the user name typed in the sign in screen.
Authorization Settings
When using LDAP, the user information and privileges for GeoNetwork could be defined from the LDAP attributes.
User information
The user information could be retrieved from the LDAP configuring for each user attribute in the catalog database which LDAP attributes match. If the attribute is empty or not defined, a default value could be defined. The property value is composed by two parts separated by ,
character. The first part is the attribute name and the second part is the default value in case the attribute name is not define or the attribute value in LDAP is empty.
The configuration is the following:
# Map user information to LDAP attributes and default values
# ldapUserContextMapper.mapping[name]=ldap_attribute,default_value
ldapUserContextMapper.mapping[name]=cn,
ldapUserContextMapper.mapping[surname]=givenName,
ldapUserContextMapper.mapping[mail]=mail,data@myorganization.org
ldapUserContextMapper.mapping[organisation]=,myorganization
ldapUserContextMapper.mapping[kind]=,
ldapUserContextMapper.mapping[address]=,
ldapUserContextMapper.mapping[zip]=,
ldapUserContextMapper.mapping[state]=,
ldapUserContextMapper.mapping[city]=,
ldapUserContextMapper.mapping[country]=,
Privileges configuration
User groups and user profiles could be set optionally from LDAP information or not. By default user privileges are managed from the local database. If LDAP information should be used to define user privileges, set the ldap.privilege.import
property true
:
When importing privileges from LDAP, the catalog administrator could decide to create groups defined in the LDAP and not defined in local database. For this set the following property to true:
In order to define which groups the user is member of and which profile is the user:
ldapUserContextMapper.mapping[privilege]=groups,sample
# If not set, the default profile is RegisteredUser
# Valid profiles are http://geonetwork-opensource.org/manuals/trunk/eng/developer/apidocs/geonetwork/org/fao/geonet/constants/Geonet.Profile.html
ldapUserContextMapper.mapping[profile]=privileges,RegisteredUser
Attributes configuration:
- privilege attribute contains the group this user is member of. More than one group is allowed.
- profile attribute contains the profile of the user.
User valid profiles are:
- Administrator
- UserAdmin
- Reviewer
- Editor
- RegisteredUser
- Guest
If LDAP attribute containing profiles does not match the catalog profile list, a mapping could be defined:
# Map LDAP custom profiles to catalog profiles. Not used if ldap.privilege.pattern is defined.
ldapUserContextMapper.profileMapping[Admin]=Administrator
ldapUserContextMapper.profileMapping[Editor]=Reviewer
ldapUserContextMapper.profileMapping[Public]=RegisteredUser
For example, in the previous configuration, the attribute value Admin
will be mapped to Administrator
(which is a valid profile for the catalog).
An attribute could define both the profile and the group for a user. To extract this information, a custom pattern could be defined to populate user privileges according to that attribute:
-
Define one attribute for the profile and one for groups in
WEB-INF/config-security/config-security-overrides.properties
-
Define one attribute for the privilege and define a custom pattern:
# In config-security.properties ldap.privilege.pattern=CAT_(.*)_(.*) ldap.privilege.pattern.idx.group=1 ldap.privilege.pattern.idx.profil=2
Enable the bean
er
forLDAPUserDetailsContextMapperWithPattern
( inWEB-INF/config-security/config-security-ldap.xml
).<!--<bean id="ldapUserContextMapper" class="org.fao.geonet.kernel.security.ldap.LDAPUserDetailsContextMapper"> <property name="mapping"> <map/> </property> <property name="profileMapping"> <map/> </property> <property name="ldapBaseDn" value="${ldap.base.dn}"/> <property name="importPrivilegesFromLdap" value="${ldap.privilege.import}"/> <property name="createNonExistingLdapGroup" value="${ldap.privilege.create.nonexisting.groups}"/> <property name="createNonExistingLdapUser" value="${ldap.privilege.create.nonexisting.users}"/> <property name="ldapManager" ref="ldapUserDetailsService"/> <property name="contextSource" ref="contextSource"/> <property name="ldapUsernameCaseInsensitive" value="${ldap.usernameCaseInsensitive:#{true}}"/> </bean>--> <bean id="ldapUserContextMapper" class="org.fao.geonet.kernel.security.ldap.LDAPUserDetailsContextMapperWithPattern"> <property name="mapping"> <map/> </property> <property name="profileMapping"> <map/> </property> <property name="importPrivilegesFromLdap" value="${ldap.privilege.import}"/> <property name="createNonExistingLdapGroup" value="${ldap.privilege.create.nonexisting.groups}" /> <property name="createNonExistingLdapUser" value="${ldap.privilege.create.nonexisting.users}" /> <property name="ldapManager" ref="ldapUserDetailsService" /> <property name="privilegePattern" value="${ldap.privilege.pattern}" /> <property name="groupIndexInPattern" value="${ldap.privilege.pattern.idx.group}"/> <property name="profilIndexInPattern" value="${ldap.privilege.pattern.idx.profil}"/> <property name="contextSource" ref="contextSource" /> </bean>
-
Define custom location for extracting group and role (no support for group/role combination) (use LDAPUserDetailsContextMapperWithProfileSearch in
config-security.xml
).ldap.privilege.search.group.attribute=cn ldap.privilege.search.group.object=ou=groups #ldap.privilege.search.group.query=(&(objectClass=*)(memberUid=uid={0},${ldap.base.search.base},${ldap.base.dn})(cn=EL_*)) ldap.privilege.search.group.queryprop=memberuid ldap.privilege.search.group.query=(&(objectClass=*)(memberUid=uid={0},${ldap.base.search.base},${ldap.base.dn})(|(cn=SP_*)(cn=EL_*))) ldap.privilege.search.group.pattern=EL_(.*) ldap.privilege.search.privilege.attribute=cn ldap.privilege.search.privilege.object=ou=groups ldap.privilege.search.privilege.query=(&(objectClass=*)(memberUid=uid={0},${ldap.base.search.base},${ldap.base.dn})(cn=SV_*)) ldap.privilege.search.privilege.pattern=SV_(.*)
The LDAP attribute can contains the following configuration to define the different type of users, for example:
cat_privileges=CAT_ALL_Administrator -- Define a reviewer for the group GRANULAT cat_privileges=CAT_GRANULAT_Reviewer -- Define a reviewer for the group GRANULAT and editor for MIMEL cat_privileges=CAT_GRANULAT_Reviewer cat_privileges=CAT_MIMEL_Editor -- Define a reviewer for the group GRANULAT and editor for MIMEL and RegisteredUser for NATURA2000 cat_privileges=CAT_GRANULAT_Reviewer cat_privileges=CAT_MIMEL_Reviewer cat_privileges=CAT_NATURA2000_RegisteredUser -- Only a registered user for GRANULAT cat_privileges=CAT_GRANULAT_RegisteredUser
Synchronization
A synchronization task is taking care of removing LDAP users that may be deleted. For example:
- T0: User A signs in to the catalog. A local user A is created in the user database.
- T1: User A is deleted from the LDAP (User A cannot sign in to the catalog anymore).
- T2: The synchronization task will check that all local LDAP users exist in LDAP:
- If the user does not own any records, it will be deleted.
- If the user owns metadata records, a warning message will be written to the catalog logging system. The owner of the record should be changed to another user before the task can remove the current owner.
By default the task runs once every day. This can be changed in the following property:
The following properties allow advanced configuration of the synchronisation process:
ldap.sync.user.search.base=${ldap.base.search.base}
ldap.sync.user.search.filter=(&(objectClass=*)(mail=*@*)(givenName=*))
ldap.sync.user.search.attribute=uid
ldap.sync.group.search.base=ou=groups
ldap.sync.group.search.filter=(&(objectClass=posixGroup)(cn=EL_*))
ldap.sync.group.search.attribute=cn
ldap.sync.group.search.pattern=EL_(.*)
Debugging
If the connection fails, try to increase the logging level for LDAP in WEB-INF/classes/log4j.xml
:
Or from the Configuration Settings set the Log level
to DEV
temporarily:
Configuring LDAP - Hierarchy
A slightly different method for LDAP configuration was introduced in mid-2020.
This extends the original configuration infrastructure (original configurations still work without any changes).
Before you start configuring, you will need to know;
- URL to your LDAP Server
- Username/password to login to the LDAP Server (to execute queries)
- LDAP query to find a user (given what they type in on the login screen)
- Details of how to convert the LDAP user's attributes to GeoNetwork user attributes
- LDAP query to find groups a user is a member of
- How to convert a LDAP group to a GeoNetwork Group/Profile
Note
There is a video developer chat that goes into details for how to configure LDAP including setting up a pre-configured LDAP server (using Apache Directory Studio) for testing/debugging/learning.
Note
Should I use the Hierarchy or Original configuration?
If you already have an existing (Original) configuration, there's no need to move to the new one. Most of the code between the two is the same.
If you are starting a new configuration, I would recommend the Hierarchy configuration. It's a little simpler and supported by test cases and test infrastructure. It also supports LDAPs where users/groups are in multiple directories.
Configuring LDAP Beans (Hierarchy)
GeoNetwork comes with a sample LDAP configuration that you can use in Apache Directory Studio to create the same LDAP server used in the test cases. There is also a sample GeoNetwork configuration that connects to this LDAP server. Please see core-geonetwork/blob/master/core/src/test/resources/org/fao/geonet/kernel/security/ldap/README.md
or the video developer chat for instructions.
Note
To use this configuration, uncomment the "web/src/main/webapp/WEB-INF/config-security/config-security.xml
-
Configure the
ce
bean with a reference to your LDAP server and a user that can execute LDAP queries.<bean id="contextSource" class="org.springframework.security.ldap.DefaultSpringSecurityContextSource"> <constructor-arg value=“ldap://localhost:3333/dc=example,dc=com"/> <property name="userDn" value="cn=admin,ou=GIS Department,ou=Corporate Users,dc=example,dc=com"/> <property name="password" value="admin1"/> </bean>
-
Configure the
ch
bean with the query used to find the user (given what was typed in the login page).NOTE: Set
ee
toue
to do a recursive search of the LDAP. Usese
to control which directory the search starts in ("" means start from the root). -
Configure the
er
bean with how to convert the LDAP user's attributes to GeoNetwork user attributes (see the original configuration documentation, above).NOTE: The
ue
portion has two parts. The first part is the name of LDAP attribute (can be blank). The second part is the default value if the LDAP attribute is missing or empty (see the original configuration documentation, above).<bean id="ldapUserContextMapper" class=“LDAPUserDetailsContextMapperWithProfileSearchEnhanced"> <property name="mapping"> <map> <entry key="name" value="cn,"/> <entry key="surname" value="sn,"/> <entry key="mail" value="mail,"/> <entry key="organisation" value=","/> <entry key="address" value=","/> <entry key="zip" value=","/> <entry key="state" value=","/> <entry key="city" value=","/> <entry key="country" value=","/> <entry key="profile" value=",RegisteredUser"/> <entry key="privilege" value=",none"/> </map> </property> </bean>
-
Continue configuring the
er
bean so the LDAP can also provide group/profile roles for the user.NOTE: The
ry
is the LDAP directory where the membership query will be start ("" means start at the root of the LDAP).<bean id="ldapUserContextMapper" class="LDAPUserDetailsContextMapperWithProfileSearchEnhanced"> <property name="importPrivilegesFromLdap" value=“true"/> <!-- typically, don't want GN to modify the LDAP server! --> <property name="createNonExistingLdapGroup" value="false" /> <property name="createNonExistingLdapUser" value="false" /> <property name="ldapManager" ref="ldapUserDetailsService" /> <property name="membershipSearchStartObject" value=""/> <property name="ldapMembershipQuery" value="(&(objectClass=*)(member=cn={2})(cn=GCAT_*))"/> </bean>
-
Continue configuring the
er
bean so the LDAP roles can be converted to GeoNetwork Groups/Profiles.NOTE: You can use multiple
rs
.
There are currently two ways to convert an LDAP group to GeoNetwork Groups/Profiles.
-
The
er
, which works the same as the original LDAP configuration. It uses a regular expression to parse the LDAP group name into a GeoNetwork Group/Profile. This will convert the LDAP roleOR
into the GeoNetwork groupAL
with Profiler.
<bean id="ldapRoleConverterGroupNameParser" class="LDAPRoleConverterGroupNameParser"> <property name="ldapMembershipQueryParser" value="GCAT_(.*)_(.*)"/> <property name="groupIndexInPattern" value="1"/> <property name="profileIndexInPattern" value=“2"/> <property name="profileMapping"> <map> <entry key="ADMIN" value="Administrator"/> <entry key="EDITOR" value="Editor"/> </map> </property> </bean>
-
There is also a more direct way using
er
. This directly converts the LDAP group name into a list of GeoNetwork Groups/Profiles.<bean id=“ldapRoleConverterGroupNameParser" class="LDAPRoleConverterGroupNameConverter"> <property name="convertMap"> <map> <entry> <key> <value>HGIS_GeoNetwork_Admin</value> </key> <list> <bean class="org.fao.geonet.kernel.security.ldap.LDAPRole"> <constructor-arg name="groupName" type="java.lang.String" value="myGroup"/> <constructor-arg name="profileName" type="java.lang.String" value="Administrator"/> </bean> </list> </entry> <entry> <key> <value>HGIS_GeoNetwork_Editor</value> </key> <list> <bean class="org.fao.geonet.kernel.security.ldap.LDAPRole"> <constructor-arg name="groupName" type="java.lang.String" value=“myGroup"/> <constructor-arg name="profileName" type="java.lang.String" value="Editor"/> </bean> </list> </entry> </map> </property> </bean>
Configuring CAS
To enable CAS, set up authentication by including WEB-INF/config-security/config-security-cas.xml
in WEB-INF/config-security/config-security.xml
, uncommenting the following lines:
CAS can use either LDAP or a database for user management. To use a database uncomment the following lines instead:
The CAS configuration is defined in WEB-INF/config-security/config-security.properties
. You can configure your environment by updating the previous file or by defining property overrides in the file WEB-INF/config-security/config-security-overrides.properties
:
cas.baseURL=https://localhost:8443/cas
cas.ticket.validator.url=${cas.baseURL}
cas.login.url=${cas.baseURL}/login
cas.logout.url=${cas.baseURL}/logout?url=${geonetwork.https.url}/
Configuring OAUTH2 OpenID Connect
OAUTH2 OpenID Connect is an authentication and authorization system based on OAUTH2. Geonetwork's OpenID Connect plugin has been tested with Keycloak and Azure AD, but should work with any provider.
Basic Setup Steps:
- Configure your IDP Server (i.e. Keycloak or Azure AD)
- Ensure that the ID Token provides role/group information
- Authorize your Geonetwork URLs for redirects (i.e.
http://localhost:8080/geonetwork/login/oauth2/code/geonetwork-oicd
) - Record the Client ID
- Record the Client Secret
- Get the Server's JSON metadata document
- Configure Geonetwork via environment variables
GEONETWORK_SECURITY_TYPE=openidconnect
OPENIDCONNECT_CLIENTSECRET=\...
(from your IDP server)OPENIDCONNECT_CLIENTID=\...
(from your IDP server)OPENIDCONNECT_SERVERMETADATA_JSON_TEXT='\...'
(the text of your Server's JSON metadata document)OPENIDCONNECT_IDTOKENROLELOCATION=\...
(location of the user's roles in the ID Token)
Geonetwork's Open ID Connect plugin has a lot of configuration options - please see the WEB-INF/config-security/config-security-openidconnect.xml
and WEB-INF/config-security/config-security-openidconnect-overrides.properties
files.
Environment Variable and Meaning
GEONETWORK_SECURITY_TYPE
Should be ct
.
OPENIDCONNECT_CLIENTID
The name of the client/application you configured on your OpenID server.
OPENIDCONNECT_CLIENTSECRET
The et
you configured on your OpenID server.
OPENIDCONNECT_SERVERMETADATA_CONFIG_URL
URL to the external OIDC server's JSON metadata document. This is typically at /.well-known/openid-configuration
on the IDP server.
Note
This will download the server's configuration everytime GeoNetwork starts up, which could be a security concern. For security, use a ps
URL.
OPENIDCONNECT_SERVERMETADATA_JSON_TEXT
Should be the text of your OpenID server's metadata configuration (JSON).
OPENIDCONNECT_SERVERMETADATA_FNAME
Instead of putting the OpenID server's metadata configuration as text in a variable (OPENIDCONNECT_SERVERMETADATA_JSON_TEXT
), you can put the JSON contents in a file and reference it with this variable (ie. /WEB-INF/config-security/openid-configuration.json
)
OPENIDCONNECT_IDTOKENROLELOCATION
Where, in the ID Token, are the users roles/groups stored (i.e. "groups", "roles", or "resource_access.gn-key.roles")
OPENIDCONNECT_ROLECONVERTER
This provides simple role conversion from the OpenID server to Geonetwork roles.
ie. "GeonetworkAdmin=Administrator,GeonetworkEditor=Editor"
This will convert "GeonetworkAdmin" (from the OpenID Server) to the Geonetwork "Administrator" role.
Note
Like the keycloak plugin, you can use role/group names of the form "group:role" to assign a user to Geonetwork group and permission level.
OPENIDCONNECT_MINIMUMPROFILE
Every user who authenticates against the OpenID server will be given this role.
Default is "RegisteredUser"
.
OPENIDCONNECT_USERPROFILEUPDATEENABLED
When a user logs on, update their Geotwork profile from the OpenID server's ID Token.
Default is "true"
.
OPENIDCONNECT_USERGROUPUPDATEENABLED
When a user logs on, update their Geotwork group/role permissions.
Default is "true"
.
OPENIDCONNECT_SCOPES
Limit the requested scope access to the OpenID server.
Default "openid email profile", and "openid email profile offline_access" (for bearer tokens).
OPENIDCONNECT_LOGINTYPE
How Geonetwork deals with users who are not logged on.
Default is "LINK" - users can click on the "login" link on the main page.
"AUTOLOGIN" - No login form provided which will automatically login the user when possible.
OPENIDCONNECT_LOGSENSITIVE_INFO
"true" or "false" (default)
Logs: CODE, ACCESS TOKEN, ID TOKEN, userinfo endpoint result, and calculated GeoNetwork authorities.
LOGGING THIS INFORMATION IS PROBABLY A SECURITY AND PERSONAL INFORMATION RISK. DO NOT TURN THIS ON IN A SYSTEM THAT IS ACTUALLY BEING USED.
We try not to log very sensitive information - we don't log the full access or id token (just the claims part). We log the single-use CODE, but it should have already been deactivated by the server before we log it.
The access token, userinfo, and id token contain sensitive information (i.e. real names, email address, etc...)
Configuration for a Keycloak Server
It's outside the scope of this document to fully describe the steps to configure keycloak, but this should serve as a guide.
This will configure keycloak backed by another OpenID IDP (for example, by an Azure AD). In keycloak:
- Create a realm (i.e.
lm
) - Create an openid client (i.e.
nt
). This is your ClientID.- Root URL:
http://localhost:7777/geonetwork
(this is the GN root URL) - Valid Redirect URIs:
http://localhost:7777/geonetwork/*
- Access Type: Confidential
- On the
ls
tab, get the secret (this is your Client Secret) - On the
es
tab, create some roles: Administrator, Editor, Reviewer, RegisteredGuest
- Root URL:
- Create your backing Identity Provider (i.e. to another OpenID server). Or you can configure users directly in keycloak.
- At the bottom of the page, choose "import from URL" and import the backing server's configuration location.
- Add the Client Secret (from the backing service)
- Add the Client ID (from the backing service)
- set "Client Authentication" to "Client secret sent as post"
- Configure role translation
- Edit the "Identity Provider" you just created, and go to the "Mappers" tab.
- Press "Create" and and add a "Claim to Role".
- Set Sync Mode Override to "Force"
- Claim:
es
- Claim Value:
DP
- Role: choose the "Administrator" role from the
nt
client. - Repeat the above for Administrator, Editor, Reviewer, and RegisteredGuest
- Configure details for your backing IDP
- Edit the "Identity Provider" you just configured
- On the Mappers tab, "Add Builtin" and tick "client roles (User Client Role)" then "Add selected"
- Edit the "client roles" mapper and make sure "Add to ID token" and "Add to userinfo" are on
You should have Keycloak's Client id ("myclient") and the client secret. The configuration JSON is available at https://YOUR_KEYCLOAK_HOST/realms/{YOUR REALM NAME}/.well-known/openid-configuration
Your environment variables will looks like this:
GEONETWORK_SECURITY_TYPE=openidconnect
OPENIDCONNECT_CLIENTSECRET='...'
OPENIDCONNECT_CLIENTID='...'
OPENIDCONNECT_SERVERMETADATA_JSON_TEXT='...big json text...'
OPENIDCONNECT_IDTOKENROLELOCATION='resource_access.{your client id}.roles'
Azure AD Configuration
There are two ways to setup Azure AD. The first is with user and groups (a more traditional LDAP method) or with Application Roles.
With Users and Groups
Setup the Azure Application:
- Create a new
on
- use
http://localhost:8080/geonetwork/login/oauth2/code/geonetwork-oicd
as a redirect URIs - On the "Certificates & Secrets" add a new secret and record it (make sure you get the secret value and NOT the object id)
- Make sure the groups are in the ID token - on the "Manifest" tab, edit the JSON so that "groupMembershipClaims": "SecurityGroup" is set
- On the summary page, get the Application (client) ID
- On the summary page, choose "Endpoints" (at the top) and get the JSON text from the "OpenID Connect metadata document" Endpoints
Setup users and groups:
- In Azure AD, go to groups
- Add new Groups - "geonetworkAdmin", "geonetworkReviewer", etc... Record the name and the group's Object ID
- Edit a User, and choose Groups, and add them to appropriate group.
Your environment variables will looks like this:
GEONETWORK_SECURITY_TYPE=openidconnect
OPENIDCONNECT_CLIENTSECRET='...'
OPENIDCONNECT_CLIENTID='...'
OPENIDCONNECT_SERVERMETADATA_JSON_TEXT='...big json text...'
OPENIDCONNECT_IDTOKENROLELOCATION='groups'
OPENIDCONNECT_ROLECONVERTER='3a94275f-7d53-4205-8d78-11f39e9ffa5a=Administrator,d93c6444-feee-4b67-8c0f-15d6796370cb=Reviewer'
Note
The roles are in the "roles" part of the ID Token.
Note
The OPENIDCONNECT_ROLECONVERTER converts the Azure AD Group's Object ID to a Geonetwork Role.
With Application Roles
Setup the Azure Application:
- Create a new Enterprise application
- use
http://localhost:8080/geonetwork/login/oauth2/code/geonetwork-oicd
as a redirect URIs - On the "Certificates & Secrets" add a new secret and record it (make sure you get the secret value and NOT the object id)
- Make sure the groups are in the ID token - on the "Manifest" tab, edit the JSON so that "groupMembershipClaims": "ApplicationGroup" is set
- On the summary page, get the Application (client) ID
- On the summary page, choose "Endpoints" (at the top) and get the JSON text from the "OpenID Connect metadata document" Endpoints
Setup Application Roles:
- In Application you created, go to "App Roles".
- Add new Groups - "Editor", "Reviewer", etc...
Assign Users:
- Go to Azure AD, Enterprise Application, then the application you created
- Choose "Assign users and groups"
- Press the "Add user/group" (top)
- Press "None Selected" (under Users) and choose some users
- Press "None Selected" (Under Select a Role) and choose some roles
- Configure all your users with roles
Your environment variables will looks like this:
GEONETWORK_SECURITY_TYPE=openidconnect
OPENIDCONNECT_CLIENTSECRET='...'
OPENIDCONNECT_CLIENTID='...'
OPENIDCONNECT_SERVERMETADATA_JSON_TEXT='...big json text...'
OPENIDCONNECT_IDTOKENROLELOCATION='roles'
Note
The roles are in the "roles" part of the ID Token.
Note
You don't typically have to do any role conversion since the role name will be used in the ID Token.
OIDC Bearer Tokens
Bearer Tokens are also supported - you can attach the JWT Bearer token to any request by setting the HTTP header like this:
Bearer Tokens are mostly used for automated (desktop or application) API calls - real users should just login normally using OIDC.
- Setup your OIDC configuration (see Configuring OAUTH2 OpenID Connect)
- Setup the OIDC Bearer token configuration (see Configuration)
- Obtain a Bearer token from the OIDC server. This is the hard part and there are several ways to do this. One way that is used is via the OAuth 2.0 Device Authorization Grant ("Device Flow") workflow.
- Attach it to your request headers (see OIDC Bearer Tokens)
- Make protected requests to the Geonetwork API
This has been tested with Keycloak and with Azure AD. It should work with other JWT-based OIDC services.
Validation
The token is validated in three major ways:
- The bearer token will be used to access the
fo
("token validation") endpoint specified in the OIDC configuration. This means the IDP validates the token (at the very least its signature and expiry). - The bearer token (JWT) will be checked that the audience for it is the same as our configurated OIDC configuration. This will ensure that someone isn't getting a token from a different service and attempting to use it here. See
AudienceAccessTokenValidator.java
- The bearer token (JWT) will be checked that the subject of the JWT and the
fo
(returned from the IDP) are the same. This shouldnt be a problem in our use-case, but the OAUTH2 specification recommends this check. SeeSubjectAccessTokenValidator.java
Configuration
Configure OIDC as above - ensure this is working.
Instead of using GEONETWORK_SECURITY_TYPE=openidconnect
, use GEONETWORK_SECURITY_TYPE=openidconnectbearer
.
Inside WEB-INF/config-security/config-security-openidconnectbearer.xml
:
- If you are using keycloak (configured with Groups in the
fo
response), then uncomment theer
bean and comment out theer
bean. - If you are using Azure AD (MS Graph API for the user's groups), then then uncomment the
er
bean and comment out theer
bean.
The easiest way to test is to obtain a Bearer Token, and then use a browser plugin to add the Authorization: Bearer <token>
header to all requests. When you visit the Geonetwork website, you should see yourself logged in with the appropriate permissions.
Other Providers
This has been tested with Azure AD (groups in the MS Graph API) and KeyCloak (groups in the fo
).
For other IDP, you might have to make some modifications.
- Make sure the
or
andor
work correctly for your JWT bearer tokens. - Make sure that the user's groups are available - see the
er
interface and its two implementations -er
ander
.
Configuring Keycloak
Keycloak is a software solution to facilitate storage of authentication details, user federation, identity brokering and social login. GeoNetwork can be set up to use a keycloak instance for authentication.
Install keycloak from its instructions or use this example setup in docker https://www.keycloak.org/getting-started/getting-started-docker
Keycloak details are defined via environment variables
KEYCLOAK_AUTH_SERVER_URL={keycloak url}
KEYCLOAK_REALM={realm name}
KEYCLOAK_RESOURCE={client name}
KEYCLOAK_SECRET={client secret}
KEYCLOAK_DISABLE_TRUST_MANAGER={true|false}
You can setup more advance keycloak settings by editing the file WEB-INF/config-security/keycloak.json
Geonetwork client URL configuration
Ensure that when you configure your client that you setup the valid redirect uris to your geonetwork installation. i.e. https://localhost:8443/geonetwork/*
. If this is not setup correctly you may get and error indicating that a wrong redirect uri was supplied. Also if wanting to test the client backchannel logout then ensure that the admin URL is also set to the geonetwork installation.
Sample user/role/group setup
Sample Role setup
In your client role settings (clients -> myclient -> roles). Add the following roles
Administrator
RegisteredUser
Guest
sample:UserAdmin
sample:Reviewer
sample:Editor
sample:RegisteredUser
Sample Group configuration
- Go to keycloak groups (left menu).
- Create a new group called "Administrator"
- Edit the group. Go to Role Mappings -> Client Roles (myclient) -> select the administrator roles and click on "Add selected" Any user joined to the Administrator group will be a geonetwork administrator.
Sample User configuration
- Go to keycloak users (left menu)
- Add or select existing user. Then go to that user.
- Go to role Mappings -> Client Roles (myclient) -> select the available roles to be applied and click on "Add selected" or go to Groups -> Available Groups -> Click on the Administrator Group and then click on "Join"
A similar setup is described for geoserver in the geoserver documentation.
Configuring EU Login
EU Login is the central login mechanism of the European Commission. You can enable login against that central service in case your intended users have ar can acquire a EU Login.
To enable EU Login, set up authentication by including WEB-INF/config-security/config-security-ecas.xml
in WEB-INF/config-security/config-security.xml
, uncommenting the following line:
EU-login requires an ecas-plugin provided by the European Union. The ecas plugin is available via CITnet for various java containers, such as Tomcat and JBoss.
For tomcat, add two files to the tomcat lib folder: ecas-tomcat-x.y.z.jar and log4j-x.y.z.jar. Inside the lib folder copy two folders from eulogin-tomcat-x.y.z-config.zip
: org/apache/catalina/authenticator
and org/apache/catalina/startup
. The mbeans folder contains a file mbeans-descriptors.xml
. The startup folder contains a file Authenticators.properties
. Verify that the JDK trusts the ECAS certificates else import them on the keystore of the JVM.
The EU Login configuration is defined in WEB-INF/config-security/config-security.properties
. You can configure your environment by updating the previous file or by defining property overrides in the file WEB-INF/config-security/config-security-overrides.properties
:
Restart the service and check the authentication menchanism.
Configuring Shibboleth
The catalog can operate in a SAML secured federation. Shibboleth should be installed in Apache as described here. The catalog is accessed via Apache. Setup Shibboleth authentication by including WEB-INF/config-security/config-security-shibboleth.xml
in WEB-INF/config-security/config-security.xml
. You can then configure your environment in config-security-shibboleth-overrides.properties
.