Description from Bugzilla Bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=535381:
OpenMDM delegated roles and permissions with backend connectors
What is this?
This contribution was developed by Canoo as part of a contract with two members of the OpenMDM group.
It implements the delegated approach to roles and permissions, wherein the data sources (ODS server, PAK cloud)
themselves can implement their own security scheme (which they already have) and then delegates the appropriate
user data to the backends.
In the case of ODS servers this is done using a technical user and the 'for_user' attribute on the established
connection, so it is a form of 'login on behalf'.
In the case of PAK Cloud this is done by passing the user name along with a http header 'X-Remote-User' which is then
used by PAK Cloud to establish the users roles (from an internal database or an external authentication provider).
This approach leads to some changes that need to be made to the current code of `base`, `odsadapter` and `nucleus`
The following changes have been made to the code bases/applications:
`EnumerationValue` did return null for the `name()` in some cases, which lead to the PAK Cloud adapter breaking.
the code that returns value sequences was not fully working, so we fixed it.
all `EnumerationValue` classes enforce having a `name`.
the names of the fields were used as the `name` of all `EnumerationValues`
comparison of `float` and `double` values in tests was fixed using `EPSILON`
`ODSContectFactory` needs a new parameter on the connection `for_user`
Replace idiosyncratic use/implementation of `BiDiMapper` with `ImmutableBiMap`. That class has several invariants that
make it more suitable than a custom rolled implementation: it does not allow `null` keys or values, it make sure there are
no duplicates, so the function actually is reversible and (this is a big one) it is immutable after creation. This makes
reasoning about code that uses it much simpler.
Use a CDI event to create the elasticsearch index asynchronously. This makes application startup much faster and
also (theoretically) index creation/updating triggerable later on.
use `LdapRealm` for authentication: The use of an external authentication source is actually needed here, to make
authentication in the back ends also works (for instance with PAK Cloud). Also it is a much more realistic scenario
because most environments already provide a mechanism of authentication. More on this further down.
Change `ConnectorService` to be `@SessionScoped` and not manage multiple connections for multiple users, but rather
multiple connections for a single user. This makes the class much simpler.
Use of `@Inject` instead of `@Ejb` on beans that are injected. In order for a bean to be session scoped (or use any other
CDI scope such as `@RequestScoped`) it needs to be injected via `@Inject` not `@Ejb`. This should probably be changed
for all dependency injection points.
Inject the `java.security.Principal` into `ConnectorService` and no longer rely on having a username and a password
available for back end connectors.
Greatly simplify the code of `ConnectorService`, since it only needs to keep track of connections for one session.
Add nicer logging and error handling to `ServiceConfigurationActivity`
Change the way connections to elasticsearch are established, since they now need to use the 'technical user' of the
ODS back end.
Make inclusion of project conditional on their existence, so this also builds with artifacts downloaded from a repository
such as nexus.
Changes to the surrounding environment
This change needs a few other things to work:
We created a Dockerfile for creating a docker image of ods, pre-configured and with the applications installed and libraries
patched. I'll let Angelika have it on a separate stream, as it does not (for now) directly fit in anywhere.
This version of the nucleus webapp needs an `LdapRealm` (or any other `javax.security.Realm`) to be configured
in glassfish to do the authentication and then supply the `Principal` to applications that require it.
We did this by running a version of OpenLDAP along with the dockerized version of openmdm. We would recommend
adding this to the installation guide. One can easily fabricate an enhanced image of OpenLDAP with some sample users
and groups already present.
We ran elasticsearch as a docker container along with openmdm as opposed to manually installing it on the host computer, but
this is not striclty necessary, but it makes things much easier: running it can be as simple as: `docker run elasticsearch:2.4.6-alpine`.
I can provide Angelika with the build files for a customized image of OpenLDAP, but the working group has to find itself
a docker registry (or run one) where they can publish it, so users can simply pull from there and run it.
The same registry (with an image of openmdm) could also be used for release versions of openmdm for testing and showcase purposes.
Configuring glassfish for this to work
The LDAP Realm can be added as follows (you will have to provide the relevant variables):
echo "Adding openmdm ldap security realm"
asadmin --user=admin --passwordfile=/tmp/glassfishpwd create-auth-realm \
--classname com.sun.enterprise.security.auth.realm.ldap.LDAPRealm \
--property jaas-context=ldapRealm:directory=\'$LDAP_URL\':base-dn=\'$LDAP_BASE_DN\':assign-groups=MDM:search-bind-dn=\'$LDAP_SEARCH_DN\':search-bind-password=\'$LDAP_SEARCH_PASSWORD\' \
You can also add it using the glassfish admin console giving it the same properties.
There were some questions about which user is used by the openMDM5 backend to log in to the ASAM ODS server after this change.
First the credentials of the user A are checked against the configured Glassfish realm.
After successful authentication against the realm, the ODS adapter will connect to the ODS server using the credentials of a technical ODS user B.
User B must have set the superuser flag to true and will open an ODS session on behalf of user A.
The login string would look as follows: "USER=B,PASSWORD=PWD_OF_B,FOR_USER=A"
So the credentials to open the session are from user B, but the session will have all roles and thus access rights of user A (see ASAM ODS specification 188.8.131.52).
The password of user A is not sent to the ODS server and thus not checked by the ODS server, but obviously user A has to exist in the ODS database.
Delivered with openMDM V5.0.0M4