USER MANUALS

Configuring Custom Authenticators

Virtual DataPort provides a generic security configuration, along with the flexibility to use a custom authenticator for various connection types.

A Custom Authenticator is a Virtual DataPort extension that lets you integrate your own user authentication system. Instead of relying on predefined methods like LDAP or database authentication, you can develop a Java component that validates user credentials and dynamically assigns roles and permissions. This is especially useful for implementing modern authentication protocols like OAuth or SAML, or for connecting to internal identity systems that aren’t natively supported.

Upload a Custom Authenticator to Virtual DataPort

Virtual DataPort requires the Custom Authenticator’s implementation to be provided as a JAR file.

To import this file, follow the instructions in Import the third-party jar files.

Virtual DataPort supports the use of multiple custom authenticators. While each authenticator must be implemented as a separate Java class, you can group them together into a single JAR file for easier deployment. This approach simplifies management and reduces the number of files you need to import into the Virtual DataPort server.

Each uploaded JAR file is identified by a unique name (the file name without the extension). This identifier is referred to as the jar-name and is used to reference the authenticator during configuration.

Enable Custom Authentication

To enable custom authentication, execute

SET 'com.denodo.vdb.security.CustomAuthenticator.enabled'='true';

To disable it, set the value to false.

Configuring a Custom Authenticator

To configure a custom authenticator, you must set three specific properties that tell Virtual DataPort how to locate and use your implementation.

  • Class Name: Use the fully qualified Java name of your custom authenticator’s main class to set the com.denodo.vdb.security.CustomAuthenticator.default property.

  • Classpath: Specify the classpath where the custom authenticator’s JAR file is located by setting the com.denodo.vdb.security.CustomAuthenticator.default.classpath property with the JAR file name.

  • Supported Authentication Methods: Define the specific list of authentication protocols that your custom authenticator is designed to handle by setting the Virtual DataPort property: com.denodo.vdb.security.CustomAuthenticator.default.supportedAuthMethods. Possible values are: login, saml, oauth, kerberos and dndToken.

Here’s an example of these properties being set:

SET 'com.denodo.vdb.security.CustomAuthenticator.default'='com.customImplementation.CustomAuthenticatorAny';
SET 'com.denodo.vdb.security.CustomAuthenticator.default.classpath'='all-authenticators';
SET 'com.denodo.vdb.security.CustomAuthenticator.default.supportedAuthMethods'='["saml","oauth","login"]';

Custom authenticators can work with basic security level (login), or with custom implementations of the following protocols: Kerberos, Saml, OAuth and Denodo Security Token.

Warning

If multiple authentication protocols are configured, they will be applied in the following order: Kerberos, Saml, OAuth and Denodo Security Token.

Note

If supportedAuthMethods property is not defined, only basic (login) authentication will be used.

Configuring Authenticators in Groups

To configure the authenticators to be used for different connection types, a specific configuration needs to be defined for each one. These properties are equivalent to those of the default authenticator and must be set using the appropriate SET statements.

If no Class Name is specified, the one defined in the default configuration will be used. Likewise, if no Classpath is specified, the default configuration’s classpath will be applied. However, each implementation group maintains its own distinct protocol configurations, which are specific to that group and are not inherited from the default configuration.

In the following example, the first two authenticators are configured with their own class name, classpath, and supported authentication protocols. The third authenticator, however, has none of these properties specified. If values are omitted for the class and classpath properties, their default values will be used. For the authentication protocol, however, the value login will be assumed.

SET 'com.denodo.vdb.security.CustomAuthenticator.custom.groupOne'='com.denodo.vdb.security.AuthenticatorOne';
SET 'com.denodo.vdb.security.CustomAuthenticator.custom.groupOne.classpath'='customAuthenticator1';
SET 'com.denodo.vdb.security.CustomAuthenticator.custom.groupOne.supportedAuthMethods'='["oauth"]';

SET 'com.denodo.vdb.security.CustomAuthenticator.custom.groupTwo'='com.denodo.vdb.security.AuthenticatorTwo';
SET 'com.denodo.vdb.security.CustomAuthenticator.custom.groupTwo.classpath'='customAuthenticator2';
SET 'com.denodo.vdb.security.CustomAuthenticator.custom.groupTwo.supportedAuthMethods'='["oauth","saml"]';

SET 'com.denodo.vdb.security.CustomAuthenticator.custom.groupThree'='';
SET 'com.denodo.vdb.security.CustomAuthenticator.custom.groupThree.classpath'='';
SET 'com.denodo.vdb.security.CustomAuthenticator.custom.groupThree.supportedAuthMethods'='';

Note

Both properties (class name and classpath) must be modified at the same time, that is, you cannot change only the authenticator class or the classpath. If this configuration is detected an error will be thrown.

Session Attributes

In Denodo, session attributes are key-value pairs that you can define and store in a user’s session. These attributes can set by a custom authenticator and are accessible to other components, such as views and policies, throughout the user’s connection. This provides a flexible way to pass and utilize custom, user-specific data from the client to the Denodo server.

To set session attributes, your custom authenticator’s authenticate method must return a CustomUser object that includes a Map<String, String> containing the desired attributes. The server then attaches these attributes to the authenticated session.

Example: Specifying Session Attributes

The following example demonstrates how to set a list of roles and a Map of session attributes within the authenticate method of a custom authenticator.

/**
 * Example: Specifying Session Attributes
 */
@Override
public CustomUser authenticate(String login, String token) throws CustomAuthenticationException {

     ...

    List<String> roles = new ArrayList<>(1);
    roles.add(...);

    Map<String, String> sessionAttributes = new HashMap<>();
    sessionAttributes.put("customSessionAttribute_1", "value_1");
    sessionAttributes.put("customSessionAttribute_2", "value_2");
    sessionAttributes.put("customSessionAttribute_3", "value_3");

    return new CustomUser(login, roles, sessionAttributes);
}

Set Non-Modifiable Session Attributes in Virtual DataPort

Virtual DataPort allows you to designate certain session attributes as non-modifiable. This prevents them from being altered during the user’s session.

There are two methods to specify which attributes are non-modifiable.

Using the Custom Authenticator Interface

Implement the getNonModifiableAttributes() method within your custom authenticator. This method should return a Set<String> containing the names of all attributes that should not be modifiable.

/**
 * Example: Specifying Non-Modifiable Session Attributes
 */
 @Override
 public Set<String> getNonModifiableAttributes() {
     Set<String> nonModifiableAttributes = new HashSet<>();
     nonModifiableAttributes.add("customSessionAttribute_1");
     nonModifiableAttributes.add("anotherSessionAttribute_1");

     return nonModifiableAttributes;
 }

Using a Configuration Property

You can also specify non-modifiable session attributes by setting a Virtual DataPort configuration property. This method is useful for a static set of attributes that don’t need to be managed within your Java code.

Set the com.denodo.vdb.security.CustomAuthenticator.non.modifiable.attributes property by listing the names of the attributes you want to protect, separated by commas.

For example, to make customSessionAttribute_2 and anotherSessionAttribute_2 non-modifiable, execute the following command:

SET 'com.denodo.vdb.security.CustomAuthenticator.non.modifiable.attributes'='customSessionAttribute_2,anotherSessionAttribute_2';

It is possible to use both methods simultaneously. Virtual DataPort will perform a union of the attributes specified by the method and the configuration property to determine the final set of non-modifiable attributes.

Custom Authenticator Process

Virtual DataPort delegates the authentication process to the appropriate custom authenticator based on the parameters received in the connection.

When a client establishes a connection, different parameters are specified in the driver properties to allow Virtual DataPort to delegate to the correct custom authenticator.

/**
 * Example of basic authentication
 */
 @Override
 public CustomUser authenticate(String login, String token) throws CustomAuthenticationException {

     if (login.equals(token)) {
         Map<String, String> sessionAttributes = new HashMap<>();
         List<String> roles = new ArrayList<>(1);
         roles.add("role1");

         return new CustomUser(login, roles, sessionAttributes);
     }

     throw new CustomAuthenticationException("Invalid user or password");
 }

Note

To ensure a successful login, confirm that the user’s role exists on the server and has been granted the required privileges for the databases they intend to access.

Custom Parameters: Additional Authentication Information

In some situations, a custom authenticator may need to process additional information that isn’t included in a standard authentication request. This is useful for various purposes, such as optimizing the authentication flow or enabling detailed auditing.

Custom parameters allow for the secure transfer of additional, user-defined information from the client to the Virtual DataPort custom authenticator during a connection

This process involves three key steps:

  • Client-Side Configuration: The client defines a customParameters entry in the JDBC driver’s connection properties. The value for this property must be a valid JSON string containing the key-value pairs that need to be sent.

  • Server-Side Handling: When the client attempts to connect, the Virtual DataPort server receives the customParameters JSON string. This value, along with other essential connection properties (such as user, database, userAgent, accessInterface, clientIp and webServiceName), is automatically mapped and passed to the custom authenticator.

  • Custom Authenticator Processing: Within your CustomAuthenticator implementation, specifically in the authenticate method, you can access and process these parameters. To retrieve the data, simply extract the customParameters entry from the properties map. The value is received as a JSON string, which can then be parsed to access the custom, user-specific information.

Virtual DataPort allows you to include the HTTP path and HTTP method used when executing a query through RESTful Web Services. To enable this behavior, set the property: com.denodo.restfulws.customAuthIncludePathAndMethod to true and restart Virtual DataPort.

Once enabled, any request to a published web service will include these values in the customParameters property, along with any manually specified parameters.

For example:

{
  "HTTP_Method": "GET",
  "HTTP_Path": "http://acme:9090/denodo-restfulws/administration/views/customer"
}

Example: Using ‘customParameters’ Property

For example, a connection can be done with the following JSON string into the customParameters driver property:

{"array":[1,2],"bool":true,"string":"hi","number":123,"object":{"a":"b","c":"d"}}

See the Configuring Custom Authenticators section for more details.

To read and convert these JSON parameters, you can use the following approach:

/**
 * Example of reading customParameters from CustomAuthenticator
 */
private static final String PARAM_CUSTOM_PARAMETERS = "customParameters";

@Override
public CustomUser authenticate(String login, String password, Map<String, String> properties)
        throws CustomAuthenticationException {

    // Retrieve the JSON string of custom parameters
    String customParametersJsonString = properties.get(PARAM_CUSTOM_PARAMETERS);

    JSONObject receivedJson = null;
    if (customParametersJsonString != null) {
        try {
            // Convert the JSON string to a JSONObject
            receivedJson = new JSONObject(customParametersJsonString);
            ...
        } catch (JSONException e) {
            ...
        }
    }
    ...
    return new CustomUser(...);
  }

Determining the Authentication Method

In a custom authenticator, it’s often essential to know which authentication method was used to validate a user. This is particularly relevant when your authenticator supports multiple protocols and requires different logic for each.

To retrieve this information, you can extract the authMethod entry from the properties map. This map is automatically populated by Virtual DataPort with various connection details, and it is provided as a parameter to the authenticate method.

Understanding the ‘authMethod’ Property

The value of authMethod corresponds to the specific authentication protocol used to initiate the connection. The possible values are:

Value

Authentication Protocol

login

Basic authentication (user/password)

kerberos

Kerberos authentication

saml

SAML-based authentication

oauth

OAuth-based authentication

dndToken

Denodo Token authentication

Example: Using ‘authMethod’ in the Code

This code snippet demonstrates how to retrieve the authMethod value within the authenticate method to apply different logic based on the authentication protocol.

@Override
public CustomUser authenticate(String login, String password, Map<String, String> properties) throws CustomAuthenticationException {

    // Retrieve the authentication method from the properties map
    String authMethod = properties.get("authMethod");

    // Use the value to perform method-specific authentication logic
    switch (authMethod) {
        case "login":
            // Logic for basic login authentication
            // Example: authenticate using login/password against an LDAP server
            break;
        case "saml":
            // Logic for SAML authentication
            // Example: validate a SAML assertion from a token
            break;
        case "oauth":
            // Logic for OAuth authentication
            // Example: validate an OAuth2 access token
            break;
        default:
            throw new CustomAuthenticationException("Unsupported authentication method: " + authMethod);
    }

    // Return a CustomUser object on successful authentication
    return new CustomUser(login, List.of(new String[]{"role1", "role2"});
}

By leveraging the authMethod property, your single custom authenticator implementation can handle a wide range of authentication methods, making it more robust and versatile.

Custom Authenticator Implementation

Virtual DataPort provides an API for developing custom authenticators in Java.

After developing a custom authenticator, you have to import it into the Virtual DataPort server. The section Import the third-party jar files of the Administration Guide explains how to do it.

Choosing the Right Interface

You can choose between two interfaces to implement your custom authenticator, depending on the information required for authentication.

  • ICustomAuthenticator: Implement this interface if your authentication logic only needs the user’s login and password (or token). The authenticate(String login, String token) method should contain the core logic for validating these credentials.

  • ICustomAuthenticatorExtended: Implement this interface when your authenticator requires additional properties. Virtual DataPort will provide these properties, including user, database, userAgent, accessInterface, clientIp, webServiceName, and customParameters, to the authenticate(String login, String token, Map<String, String> properties) method.

Handling Authentication Outcomes

After implementing the chosen interface, your method should handle two possible outcomes:

  • On successful authentication, the method must return a CustomUser object. This object should contain the user’s login, their assigned roles, and any session attributes you want to define for the session.

  • If authentication fails, for example due to an incorrect password or invalid credentials, the method must throw a CustomAuthenticationException.

Add feedback