The purpose of this article is to outline the problems that we are attempting to solve and the solution currently being considered, this work is being tracked under the following Jira issue: -
Currently for remote EJB invocations (Actually all invocations to the server but in this case EJB invocations are the priority) a Remoting connection is established by the client, early in establishing this connection the remote client performs authentication using SASL - once authenticated the authentication is valid for the life of the connection. As EJB invocations are received the identity on this connection is the identity used for the EJB call.
The following diagram illustrates the exising calls for remote EJB clients: -
The established connection here is a Remoting connection, the connection itself is independent of any service being accessed and on establishing the connection authentication is performed using the associated realm. Subsequently when the client connects to the EJB Container and sends a request to a deployed EJB the identity used for the EJB call is the identity taken from the underlying connection. As the authentication takes place as the connection is established the only way for the clients to send in requests as an alternative user is to establish a new connection as the new user.
A second scenario is where the call is also passed from one server to another: -
In this second scenario there is now a connection from the first server to the second server, this connection also requires authentication and the call to the EJB on the second server runs as the identity of this second connection.
These two diagrams illustrate the problems to be solved: -
- For a client to run as different identities different connections are required for each identity.
- For a server to server call the identity on the second server is the identity of the connection and not the original caller.
Before reviewing alternative solutions it is worth describing the decisions relating to the authentication of the actual connection as at the very minimum it is desirable that we do not undermine this with a solution that allows interception of the exchanges in such a way that either passwords are revealed or items are revealed that could be basis for a plain text attack.
When a client attempts to connect to the Remoting connection a challenge is sent back to the client containing a list of supported authentication SASL mechanisms that the client can select from to attempt to authenticate, the client selects on and attempts the authentication. If authentication succeeds then the client can then request to connect to the service it wished to use, if not the client is re-challenged with the list of mechanisms and this is repeated until the client either successfully authenticates or the list is exhausted.
The SASL mechanisms that are offered are selected based on the capabilities of the backing user store - as an example if we have a user store what we can query to obtain the users password or a pre-prepared hash of their password we offer the client the Digest-MD5 mechanism - however if we can only verify a supplied password but not generate the hashes required for Digest based authenitcation then PLAIN is offered as a mechanism.
A second SASL mechanism that we also support is the External mechanism, this mechanism is a special mechanism in that it automatically authenticates as an identity associated with the surrounding connection - currently we use this for ClientCert style authentication where after a TLS connection is established authentication will then proceed based on the clients certificate.
Another mechanism that we are currently adding support for is GSSAPI, this is a mechanism that authenticates a user by the use of authentication tokens with no exchange of passwords between the points involved in the authentication process.
The ability to authenticate using these different approaches where we can reduce the places where either passwords or replayable tokens are visible is the key reason why we do not want to introduce those kind of vulnerabilities in the solution to the two problems being described here.
Authentication is only presently performed on establishing the connection and is considered valid for the life of the connection.
As described above we are using SASL for the negotiated authentication process between the client and the server, there are a couple of areas of SASL that either we don't use or we only use in a limited way that we can potentially take advantage of for some of this work.
For all mechanisms supported by SASL there is both an authentication id and an authorization id in the request.
- authentication id - This is the ID of the user actually performing the authentication i.e. this is the identity of the user we are comparing the password against.
- authorization id - This is the identity that we want requests to run as, i.e. this is the identity that we load the roles for.
Presently we mandate that both of these identities are the same so whilst users authenticate as themselves they can only request that the requests are run as themselves as well.
From an AS perspective this capability of SASL starts to show some possible use when we are talking about propagating security contexts and trusting requests from other clients (in our case other servers). For any server to server connection this is most likely going to be authenticated using an identity of the server. We can now review the option of allowing the server accounts to be able to request that a request is run using a different authorization id.
This now means that for a server account say 'ServerA' we are saying that we know that 'ServerA' has the capability to authenticate the remote users so we can now configure a sub-set of the users that 'ServerA' can now ask that requests are executed on behalf of.
The external SASL mechanism is a special SASL mechanism that uses something from the connection for the authentication step, presently use this mechanism to authenticate based on the clients certificate after a TLS connection had already been established - we can do this as the TLS negotiation process also went through a verification process using the trust store to verify that the clients certificate is trusted.
When looking at the existing connections one area of solutions that will be explored below is to consider repeating the SASL process within an already authenticated connection. The External mechanism could then have another role to play in that now there is already an authenticated user associated with the connection (for these issues most likey authenticated as a server) - combined with the authorization ID as discussed above a server could authenticate using this mechanism and specify the authorization id without having to repeat the full authentication process that was performed as the connection was established.
This one is not a mechanism we are currently using but are close to being able to enable this feature - in short this is enabling Kerberos based authentication which also includes identity propagation capabilities without needing to drop to using the authorization id. For anyone really serious about security context propagation I would most likely recommend this approach - however this is very dependent on the related infrastructure so may not be a suitable as a one size fits all solution.
Where SASL is used clients are expected to provide a CallbackHandler that will be called by a mechanism to request information that is required to make the call, the idea being that these CallbackHandlers contain no data and pro-actively prompt for these values ony if they are actually required. Although at some point we would like to review the CallbackHandler API due to some deficiencies in the current API that is not a priority here.
Multi Realm Support
Presently within JBoss AS7 a single realm is used for the authentication process as the connection is established, there is a desire to support multiple realms however multiple realms on connecting to the server is currently outside the scope of this feature being considered.
However if we implement a solution that uses any form of authentication then that solution should allow for the authentication to be against different realms. The feasibility and details for this should be considered in more depth with the selected solution.
This section describes the solutions currently considered and where appropriate describes why those solutions are currently discounted, at this point this is intended to be for discussion rather than a final definitive decision.
Solution from Previous Releases
In previous AS releases unless a custom RMI socket was used the connections to the application server were not authenticated, instead the username and credential would be passed along with the EJB invocation and intercepted before the call reached the EJB - the supplied information would then be used to authenticate the remote user before allowing the call to proceed.
Where a client wanted to run as multiple identities that was fine as for each invocation a different username and password could be set for the call.
This approach also potentially allowed for the security context to be passed onto subsequent servers as the contents from this message invocation are available.
Whilst this approach does solve the problem of being able to switch identities and propagate identities it suffers from the problem that the users password is sent in the clear so should we undertake a similar solution for AS7 it would undermine the protection available from the currently available SASL mechanisms, in addition to this it is assuming that a username / password based authentication is always the approach we will want to take even though there are now alternative mechanisms in common use.
Reauthenticate The Connection
As the calls are executed as the identity of the connection one approach could be to allow the client side to initiate a re-authentication of the connection so that a different identity can be used.
Whilst this would allow a client to switch identities and it could potentially be implemented using the SASL mechanisms the biggest issue here is if the client is multi-threaded and wants to run as multiple identities concurrently. At best the client would need to maintain a pool of connections one for each identity in use and if all identities could be used at once then it is no better than the current situation.
The multi threaded client issue is also made worse in the server to server case where sharing a single connection would be a major benefit in reducing the resources used.
Above where the existing Remoting authentication is described the capabilties relating to the authorization id and the External mechanism are described, for a server to server connection we could use both of these to re-authenticate the connection to switch the authorization id to the id we wish to run as - however in a server to server environment this one identity at a time per connection issue becomes even greater.
Authentication On Invocation
Moving beyond re-authenticating the whole connection another posibility is to add authentication to the actual invocation, above the previous approach of bundling credentials with an invocation was illustrated but another option now would be to add SASL authentication to the invocation process.
For the connection re-authentication of a single client the requests would be intercepted like this: -
The authentication could be optional with one of the following being used to enable it for a request: -
- A flag from the client indicating that they want the authentication to occur.
- A failed authorization check indicating the current client does not have the required permissions so now give them an opportunity to switch to an identity that does.
Alternatively it could be mandatory for the request and where no switch is required the client could use the External mechanism to ask that the current invocation is executed as the previously authenticated identity.
For the client to server scenario it would be most likely that the client is using the SASL mechanisms that perform a full authentication i.e. one of the username password mechanisms with the client knowing the usernames and password of each of the identities it wishes to use. However if the authorization ID capability is supported there is nothing to stop clients from using it should their user be allowed to do so.
A server to server call would not look like: -
The client to server portion of the call is described above but the server to server portion of the call would either be dependent on the authorization id and possibly the External mechanism capabilties or the set up would be using GSSAPI end to end to make use of the propagation capabilities of GSSAPI. Either way existing connections are now re-used without introducing a serialization of requests over the connections as multiple requests could be executed as different users concurrently.
One point to keep in mind is that although the diagram only shows one client calling the first server there could in fact be many clients calling that server each with their own connection to the server and then a single connection between the servers.
There are a couple of down sides for this approach.
- The additional SASL challenge is deep within the protocol of the service being called, if we wanted to repeat this for further protocols e.g. JNDI, management, JMX etc... then it will need to be implemented again for each of these.
- Where on the client side a CallbackHandler may be used to supply credentials to the client side of a selected SASL mechanism - if the authentication is using a one time password the client will be prompted to supply this on each invocation.
This solution is to add a new additional service to the server, clients can choose to call this service perform a SASL authentication, recieve a token after authentication is complete and pass this token in subsequent request to ask that the invocation containing the token is executed as the authorization id from the SASL authentication previously completed.
Within this solution the majority of the new interactions are handled using this new 'Authentication Service' this service is responsible for handling a new SASL authentication process and returning an authentication token to the client. It is anticipated that a process like this would support all SASL authentication mechanisms currently supported including different authorization IDs and the alternative use of the External mechanism also described above.
As in the previous solution it is anticipated that the client would be using mechanism based on having the required information to perform the authentication as different users however it is possible that the client could have the ability to request a different authorization id.
A small change is still required for the EJB invocation in that the token needs to be passed with the request, intercepted and the real identity that token maps to retrieved from the Authentication Service.
The server to server case then looks like this: -
For the server to server call as with the previous solution the server could either make use of the External mechanism with a different authorization ID when calling the authentication service or the server could use GSSAPI if it has a forwardable GSSAPI identity - either way the server recieves back a token which it then uses on the EJB invocation.
Should other services on the server require the ability for security context propagation then the same service would be used and the only part that would need to be repeated is the passing of this security token.
By introducing a token we do not want to be introducing anything that now can be used in any form of attack based on intercepting these packets, here we have a couple of options: -
- Tie the token to the connection, replays over a different connection will be rejected - clients that re-connect will have to re-establish the connections.
- This does have an implication if a CallbackHandler is in use on the client, this may be required to cache the username and password whilst being aware of any one time password requriements.
- Investigate some form of key exchange for insecure connections so the client and server can generate their own secrets, exchange them and then allow the client to prove that it can legitimatly use the token it supplied.