When provisioning software (partly) to targets, one has to rely upon the trustworthiness of both the network and the target. Even if everything is under your control and governance, one cannot entirely be sure that unwanted access takes place. A first step in order to prevent unwanted access is authentication, which gives you the ability to verify the identity of someone. Once the identity is known, one can apply authorization in order to determine what actions are allowed and which are not. In this article, the recently added authentication layer of ACE is explained in more depth and how to configure authentication to your situation.
More details on the design of the authentication mechanism in ACE can be found in the design documentation.
By default, ACE has no form of authentication enabled. While this is sufficient for demonstration purposes, you might want to change this prior to putting ACE into production. There are three parts that need to be configured:
- the "remote services" exposed by the ACE server need to enable authentication;
- the internal client(s) (which covers the ACE server itself!) need to know what authentication mechanism should be used. For convenience, the client(s) can make use of the ConnectionFactory to create authenticated connections to the ACE server;
- the management agent, which also needs to know what credentials it can use to access the ACE server.
One of the easiest forms of authentication to use in ACE is HTTP BASIC authentication, which means that username/password credentials are sent with each request to the server. Note that this is done in clear text, so you might want to add an additional layer of security by using TLS/SSL encryption as well.
There are several endpoints exposed by the ACE server as listed in the following table, along with the endpoint(s) they expose:
|BundleServlet||provides access to the OBR (bundle repository) of ACE||/obr||o.a.a.obr.servlet|
|DeploymentServlet||handles the actual provisioning of deployment packages to a target||/deployment||o.a.a.deployment.servlet|
|LogServlet||allows any number of logs for a target to be synchronized and accessed||/auditlog2||o.a.a.server.log.servlet.factory
note: this is a configuration factory!
|RepositoryServlet||provides access to the various (artifact/feature/distribution/target) internal repositories of ACE||/repository||o.a.a.repository.servlet.
|RepositoryReplicationServlet||allows relay nodes to replicate the internal repositories of ACE||/replication||o.a.a.repository.servlet.
|RESTClientServlet||provides the RESTful interface to ACE||/client||o.a.a.client.rest|
|VaadinServlet||provides the Vaadin web interface||/ace||o.a.a.webui.vaadin|
To configure authentication, for example, for the OBR servlet, you need to edit conf/org.apache.ace.obr.servlet.cfg to edit/include the following:
# Endpoint for this servlet org.apache.ace.server.servlet.endpoint = /obr # Whether or not authentication is to be used authentication.enabled = true
Note that the authentication.enabled property allows us to enable or disable the
authentication check for this servlet.
This is the only thing that is needed to enable authentication for remote services. What authentication mechanism is to be used is up to the caller/client: it should provide the right credentials in order to pass the authentication check, see also the design documentation.
The connection factory
Now that the remote services no longer accepting unauthenticated requests, we need to configure the client(s) in order to make use of authentication as well. Note that due to the modular architecture of the ACE server, the server itself is also regarded a client meaning that it needs to be configured to use authentication as well! For convenience, the client(s) can use the ConnectionFactory supplied by ACE for creating a connection with the proper authentication credentials already configured. This also simplies the configuration at the client side significantly, as we only need to configure a single service.
The ConnectionFactory service can be configured using the PID org.apache.ace.connectionfactory (note that it is a configuration factory, accepting multiple configurations!). To configure the authentication credentials for the OBR servlet, you need to edit or create a file named obr.cfg and place it in the org.apache.ace.connectionfactory directory. For HTTP BASIC authentication, the following key/values need to be present:
# What kind of authentication should we supply authentication.type = basic # The actual credentials for basic authentication authentication.user.name = d authentication.user.password = f # What is the base URL that these credentials apply to: authentication.baseURL = http://localhost:8080/obr/
When this configuration is supplied to the ConnectionFactory, it will provide a basic HTTP authentication header to each connection created for any URL starting with "http://localhost:8080/obr/"3. To disable authentication for a particular URL, the authentication.type option can be set to none.
The management agent
The management agent itself also needs to use authentication to communicate with the remote services of the ACE server. Although it would be possible to reuse the same ConnectionFactory implementation as the server, the current implementation uses a different approach to minimize the number of dependencies. To configure authentication for the management agent, you need to supply one or more system properties4:
[localhost:~/]$ java -Dagent.connection.authtype=BASIC \ -Dagent.connection.username=d -Dagent.connection.password=f \ -Dagent.identification.agentid=target-1 \ target.jar
In order to successfully authenticate a user, it needs a corresponding User that can be obtained from the UserAdmin service. Initially, ACE imports a small set of users and roles defined in the "org.apache.ace.server.repository.factory/ace-user.cfg" configuration file. One could update this file in order to add users5, or add them, for example, by hand. Alternatively, you can also use another backend for the used UserAdmin service, that connects to a LDAP server.
If after configuring the authentication of ACE things no longer work, it can be hard to find the exact cause of this. In this section, some pointers are given to help you to find the probably cause of the problem.
- I've enabled authentication, but I can still use all services without passing any credentials!
- If you've updated the configuration files of a running server or management agent, the configuration files are not automatically picked up by default. You need to stop the server/management agent, clean its felix-cache folder and start it again.
- With authentication enabled, how can I test whether the endpoints accept my credentials?
- In order to test the remote endpoints of ACE, you can use a tool like REST client. It allows you to enter credentials for any given URL.
- After enabling authentication, I do not get any errors after starting the ACE server, but it doesn't function correctly!
- Is the connection factory properly configured? Are all authentication.type options correctly set to basic and are the username/passwords correctly set? Are the configured base URLs not overlapping each other (e.g.: baseURL = http://localhost:8080/ and baseURL = http://localhost:8080/obr)?
- After enabling authentication, the management agent(s) no longer functions/I do not see them added in the web UI.
- Did you pass the auth=/path/to/config/file(s) option to the management agent to configure the connection factory? Are those files correctly stating the "authentication.type = basic", including the username and password for the desired URLs? Can you access the URLs mentioned in the configuration files with a tool like REST client?
- I do not want basic HTTP authentication, I want to use (fill in the kind of authentication)!
- Instead, you can also use two-way SSL using client certificates, but you can add your own authentication processor as well. See the design documentation for more details.
The common prefix of the shown configuration PIDs are abbreviated, so "o.a.a" stands for "org.apache.ace". ↩
Amongst others, any number of log-endpoints can be defined, at least one is needed for the audit log to be synchronized between target and ACE server. ↩
Currently, a simple String#startsWith() is used to determine whether or not a URL matches a configuration. This might change in the future when a more sophisticated URL-matching strategy is needed. ↩
Make sure to clean the bundle-cache directory before restarting the server, otherwise the new configuration files will not be picked up! ↩