com.pushtechnology.diffusion.client.security.authentication.Authenticator Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2023 DiffusionData Ltd., All Rights Reserved.
*
* Use is subject to license terms.
*
* NOTICE: All information contained herein is, and remains the
* property of Push Technology. The intellectual and technical
* concepts contained herein are proprietary to Push Technology and
* may be covered by U.S. and Foreign Patents, patents in process, and
* are protected by trade secret or copyright law.
*******************************************************************************/
package com.pushtechnology.diffusion.client.security.authentication;
import java.util.Map;
import com.pushtechnology.diffusion.client.Diffusion;
import com.pushtechnology.diffusion.client.features.Security;
import com.pushtechnology.diffusion.client.session.Session;
import com.pushtechnology.diffusion.client.types.Credentials;
/**
* An authentication handler that processes authentication requests from the
* server.
*
* Instances can be registered with the server using the
* {@link com.pushtechnology.diffusion.client.features.control.clients.AuthenticationControl#setAuthenticationHandler(String, com.pushtechnology.diffusion.client.features.control.clients.AuthenticationControl.ControlAuthenticator)
* AuthenticationControl} feature.
*
* The server calls an authentication handler when a client application creates
* a session, or changes the principal associated with a session, allowing the
* handler to veto individual requests.
*
* Authentication handlers are configured in precedence order. Authentication
* will succeed if a handler responds by calling {@link Callback#allow()
* allow()} or {@link Callback#allow(Map) allow(Map)} and handlers with higher
* precedence respond by calling {@link Callback#abstain() abstain()}.
*
* Authentication will fail if a handler responds by calling
* {@link Callback#deny() deny()} and all higher precedence handlers respond by
* calling {@link Callback#abstain() abstain()}.
*
* If all authentication handlers respond by calling {@link Callback#abstain()
* abstain()}, the request will be denied. Once the outcome is known, the server
* can choose not to call any remaining authentication handlers.
*
* @author DiffusionData Limited
* @since 6.2
*/
public interface Authenticator {
/**
* Processes an authentication request.
*
* This method will be called to authenticate new sessions, and when a
* session requests that the session principal is changed (for example,
* using {@link Security#changePrincipal changePrincipal}).
*
* For each call to {@code authenticate}, the handler should respond by
* calling one of the methods of the provided {@link Callback callback}. The
* handler can return immediately and process the authentication request
* asynchronously. The authentication will not proceed until a callback
* method is called.
*
* The content of the {@code sessionProperties} parameter depends upon
* whether the authentication handler is being called on initial
* authentication of a session or as a result of a session re-authenticating
* using {@link Security#changePrincipal changePrincipal}, as shown
* below:
*
*
*
*
* Initial Authentication
* changePrincipal
*
*
* Fixed Properties
* A full set of fixed session properties as defined in {@link Session}.
*
* {@code $Principal} will be the same as the supplied {@code principal}.
*
* {@code $Roles} will contain the configured default roles for the
* principal.
* A full set of fixed session properties as defined in {@link Session}.
*
* {@code $Principal} will be the principal from the previously
* authenticated session which can differ from the supplied
* {@code principal}.
*
* {@code $Roles} will contain the configured default roles for the new
* principal.
*
*
* User-defined Properties
* None
* Existing user-defined properties
*
*
*
* On initial authentication the {@code proposedProperties} parameter will
* provide any user-defined properties that the client supplied when opening
* the client session, but on re-authentication it will be empty
*
* The handler can choose to call {@link Callback#allow() allow()} to accept
* the authentication request with default behavior or
* {@link Callback#allow(Map) allow(Map)} to accept the authentication
* request with modifications to the session properties. Alternatively it
* can call {@link Callback#deny() deny()} to deny the request or
* {@link Callback#abstain() abstain()} to abstain from authentication, in
* which case the request will be passed on to the next configured
* authentication handler.
*
* If the handler calls {@link Callback#allow() allow()} then the resulting
* session properties for the session will be as follows:
*
*
*
* Initial Authentication
* changePrincipal
*
*
* Fixed Properties
* As supplied plus those assigned by the server on connection.
* As supplied but with {@code $Principal} replaced by the supplied
* {@code principal}.
*
*
* User-defined Properties
* None
* None
*
*
*
* If the handler calls {@link Callback#allow(Map) allow(Map)} then the map
* can contain values for any fixed properties that can be changed/supplied
* (see below) and/or all user-defined properties to assign to the session.
* The user-defined properties can be those proposed by the client or any
* set of user-defined properties that the handler chooses.
*
Permitted fixed property adjustments
*
* An authentication handler can set values for any of the following fixed
* properties to {@link Callback#allow(Map) allow(Map)}:
*
* - {@link Session#COUNTRY $Country}
*
- {@link Session#LANGUAGE $Language}
*
- {@link Session#LATITUDE $Latitude}
*
- {@link Session#LONGITUDE $Longitude}
*
- {@link Session#PRINCIPAL $Principal}
*
- {@link Session#ROLES $Roles}
*
* An authentication handler can only set values of these fixed properties.
* Other fixed properties provided by the handler will be ignored. If the
* handler does not set a fixed property, the value will be as supplied, or
* as assigned by the server.
* Handling the {@code $Roles} property
*
* The {@code $Roles} property is formatted as a quoted list of strings. To
* make the handling of this property value easier there are methods on the
* {@link Diffusion} singleton. Using these methods an authenticator can
* adjust roles as follows:
*
*
* final Set<String> roles =
* Diffusion.stringToRoles(sessionProperties.get(Session.ROLES));
* ... changes roles are required ...
* sessionProperties.put(Session.ROLES, Diffusion.rolesToString(roles));
* callback.allow(sessionProperties);
*
*
* @param principal the name of the proposed principal, or
* {@link Session#ANONYMOUS ANONYMOUS} if none was supplied
*
* @param credentials authenticating the principal; for example, a password
*
* @param sessionProperties supplies the currently known session properties
* for the client. On initial authentication this will be the known
* fixed property values. If the session is re-authenticating using
* {@link Security#changePrincipal changePrincipal}, this will be the
* full set of fixed property values plus any user-defined properties
* from the existing session. Modifications made to this map by the
* authenticator are ignored unless the map is passed to the
* {@link Callback#allow(Map) allow} method.
*
* @param proposedProperties provides any user-defined properties proposed
* by the client. The handler can choose to pass on these properties
* as they are, veto some properties, or add more properties before
* passing them to the result. The client can provide arbitrary keys
* and values. Supplied properties should be checked and
* filtered/constrained to ensure they do not affect the integrity of
* the application. Authentication handlers should not blindly pass
* proposed properties to the {@link Callback#allow(Map) allow}
* method. Modifications made to this map by the authenticator are
* ignored unless the map is passed to the {@link Callback#allow(Map)
* allow} method.
*
* @param callback single use callback
*/
void authenticate(
String principal,
Credentials credentials,
Map sessionProperties,
Map proposedProperties,
Callback callback);
/**
* Single-use callback provided to the {@link Authenticator#authenticate
* authenticate} call.
*/
interface Callback {
/**
* Authentication passed - allow the authentication request with
* modified fixed session properties and/or specified user-defined
* properties.
*
* A map comprising fixed properties to be changed and/or user-defined
* properties to be added to the session must be passed to this method.
* Only user-defined properties that are explicitly passed via this map
* will be added to the session.
*
* For convenience, either the {@code sessionProperties} map or the
* {@code proposedProperties} map passed to the
* {@link Authenticator#authenticate authenticate} method can be
* modified in order to create a suitable map to be passed to this
* method. For example, if fixed properties only are to be changed then
* the relevant properties in the {@code sessionProperties} map can be
* altered before passing that map to this method (properties that are
* not changed will be ignored). If no fixed properties are to be
* changed but user-defined properties have been proposed and are
* acceptable then the {@code proposedProperties} map can be passed to
* this method. Properties can be added to or removed from the
* {@code proposedProperties} map before passing to this method.
*
* @param properties specifies user defined properties and/or any
* changes to fixed session properties. User defined properties
* can include those from the proposed properties or additional
* properties. Proposed properties not included in this map will
* not be added to the session. See
* {@link Authenticator#authenticate authenticate}.
*
* @throws IllegalStateException if another method has already been
* invoked on this callback
*/
void allow(Map properties);
/**
* Authentication passed - allow the authentication request with fixed
* properties as supplied but no user-defined properties.
*
* If this method is used, any proposed properties passed to the
* authenticator will not be added to the session.
*
* @throws IllegalStateException if another method has already been
* invoked on this callback
*/
void allow();
/**
* The authentication has neither passed nor failed.
*
* @throws IllegalStateException if another method has already been
* invoked on this callback
*/
void abstain();
/**
* Authentication failed - deny the authentication request.
*
* @throws IllegalStateException if another method has already been
* invoked on this callback
*/
void deny();
}
}