credentialProvider;
+
+ /**
+ * {@inheritDoc}
+ *
+ * Azure Key Vault allows strictly a-z, A-Z, 0-9, and "-". This
+ * implementation strips out all contiguous groups of characters which are
+ * not allowed by Azure Key Vault, replacing them with a single dash.
+ */
+ @Override
+ public String canonicalize(String name) {
+ Matcher disallowed = DISALLOWED_CHARACTERS.matcher(name);
+ return disallowed.replaceAll("-");
+ }
+
+ @Override
+ public String getValue(String name) throws GuacamoleException {
+
+ try {
+
+ // Retrieve configuration information necessary for connecting to
+ // Azure Key Vault
+ String url = confService.getVaultURL();
+ KeyVaultCredentials credentials = credentialProvider.get();
+
+ // Authenticate against Azure Key Vault
+ KeyVaultClient client = new KeyVaultClient(credentials);
+
+ // Retrieve requested secret
+ SecretBundle secret = client.getSecret(url, name);
+
+ // FIXME: STUB
+ return null;
+
+ }
+ catch (AzureKeyVaultAuthenticationException e) {
+ throw new GuacamoleServerException("Unable to authenticate with Azure.", e);
+ }
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-vault/modules/guacamole-auth-vault-azure/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-vault/modules/guacamole-auth-vault-azure/src/main/resources/guac-manifest.json
new file mode 100644
index 000000000..87e1b1165
--- /dev/null
+++ b/extensions/guacamole-auth-vault/modules/guacamole-auth-vault-azure/src/main/resources/guac-manifest.json
@@ -0,0 +1,16 @@
+{
+
+ "guacamoleVersion" : "1.4.0",
+
+ "name" : "Azure Key Vault",
+ "namespace" : "azure-keyvault",
+
+ "authProviders" : [
+ "org.apache.guacamole.auth.vault.azure.AzureKeyVaultAuthenticationProvider"
+ ],
+
+ "translations" : [
+ "translations/en.json"
+ ]
+
+}
diff --git a/extensions/guacamole-auth-vault/modules/guacamole-auth-vault-base/.ratignore b/extensions/guacamole-auth-vault/modules/guacamole-auth-vault-base/.ratignore
new file mode 100644
index 000000000..e69de29bb
diff --git a/extensions/guacamole-auth-vault/modules/guacamole-auth-vault-base/pom.xml b/extensions/guacamole-auth-vault/modules/guacamole-auth-vault-base/pom.xml
new file mode 100644
index 000000000..d59754fe6
--- /dev/null
+++ b/extensions/guacamole-auth-vault/modules/guacamole-auth-vault-base/pom.xml
@@ -0,0 +1,70 @@
+
+
+
+
+ 4.0.0
+ org.apache.guacamole
+ guacamole-auth-vault-base
+ jar
+ guacamole-auth-vault-base
+ http://guacamole.apache.org/
+
+
+ UTF-8
+
+
+
+ org.apache.guacamole
+ guacamole-auth-vault
+ 1.4.0
+ ../../
+
+
+
+
+
+
+ org.apache.guacamole
+ guacamole-ext
+ provided
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+
+
+ com.google.inject
+ guice
+
+
+ com.google.inject.extensions
+ guice-assistedinject
+
+
+
+
+
diff --git a/extensions/guacamole-auth-vault/modules/guacamole-auth-vault-base/src/main/java/org/apache/guacamole/auth/vault/VaultAuthenticationProvider.java b/extensions/guacamole-auth-vault/modules/guacamole-auth-vault-base/src/main/java/org/apache/guacamole/auth/vault/VaultAuthenticationProvider.java
new file mode 100644
index 000000000..0b9126a67
--- /dev/null
+++ b/extensions/guacamole-auth-vault/modules/guacamole-auth-vault-base/src/main/java/org/apache/guacamole/auth/vault/VaultAuthenticationProvider.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.auth.vault;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.auth.vault.user.VaultUserContextFactory;
+import org.apache.guacamole.net.auth.AbstractAuthenticationProvider;
+import org.apache.guacamole.net.auth.AuthenticatedUser;
+import org.apache.guacamole.net.auth.Credentials;
+import org.apache.guacamole.net.auth.UserContext;
+
+/**
+ * AuthenticationProvider implementation which automatically injects tokens
+ * containing the values of secrets retrieved from a vault.
+ */
+public abstract class VaultAuthenticationProvider
+ extends AbstractAuthenticationProvider {
+
+ /**
+ * Factory for creating instances of the relevant vault-specific
+ * UserContext implementation.
+ */
+ private final VaultUserContextFactory userContextFactory;
+
+ /**
+ * Creates a new VaultAuthenticationProvider which uses the given module to
+ * configure dependency injection.
+ *
+ * @param module
+ * The module to use to configure dependency injection.
+ */
+ protected VaultAuthenticationProvider(VaultAuthenticationProviderModule module) {
+ Injector injector = Guice.createInjector(module);
+ this.userContextFactory = injector.getInstance(VaultUserContextFactory.class);
+ }
+
+ @Override
+ public UserContext decorate(UserContext context,
+ AuthenticatedUser authenticatedUser, Credentials credentials)
+ throws GuacamoleException {
+ return userContextFactory.create(context);
+ }
+
+}
diff --git a/extensions/guacamole-auth-vault/modules/guacamole-auth-vault-base/src/main/java/org/apache/guacamole/auth/vault/VaultAuthenticationProviderModule.java b/extensions/guacamole-auth-vault/modules/guacamole-auth-vault-base/src/main/java/org/apache/guacamole/auth/vault/VaultAuthenticationProviderModule.java
new file mode 100644
index 000000000..9e5ae7155
--- /dev/null
+++ b/extensions/guacamole-auth-vault/modules/guacamole-auth-vault-base/src/main/java/org/apache/guacamole/auth/vault/VaultAuthenticationProviderModule.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.auth.vault;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.assistedinject.FactoryModuleBuilder;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.auth.vault.user.VaultUserContext;
+import org.apache.guacamole.auth.vault.user.VaultUserContextFactory;
+import org.apache.guacamole.environment.Environment;
+import org.apache.guacamole.environment.LocalEnvironment;
+import org.apache.guacamole.net.auth.UserContext;
+
+/**
+ * Guice module which configures injections specific to the base support for
+ * key vaults. When adding support for a key vault provider, a subclass
+ * specific to that vault implementation will need to be created.
+ *
+ * @see AzureKeyVaultAuthenticationProviderModule
+ */
+public abstract class VaultAuthenticationProviderModule extends AbstractModule {
+
+ /**
+ * Guacamole server environment.
+ */
+ private final Environment environment;
+
+ /**
+ * Creates a new VaultAuthenticationProviderModule which configures
+ * dependency injection for the Azure Key Vault authentication provider.
+ *
+ * @throws GuacamoleException
+ * If an error occurs while retrieving the Guacamole server
+ * environment.
+ */
+ public VaultAuthenticationProviderModule() throws GuacamoleException {
+ this.environment = LocalEnvironment.getInstance();
+ }
+
+ /**
+ * Configures injections for interfaces which are implementation-specific
+ * to the vault service in use. Subclasses MUST provide a version of this
+ * function which binds concrete implementations to the following
+ * interfaces:
+ *
+ * - VaultConfigurationService
+ * - VaultSecretService
+ *
+ * @see AzureKeyVaultAuthenticationProviderModule
+ */
+ protected abstract void configureVault();
+
+ /**
+ * Returns the instance of the Guacamole server environment which will be
+ * exposed to other classes via dependency injection.
+ *
+ * @return
+ * The instance of the Guacamole server environment which will be
+ * exposed via dependency injection.
+ */
+ protected Environment getEnvironment() {
+ return environment;
+ }
+
+ @Override
+ protected void configure() {
+
+ // Bind Guacamole server environment
+ bind(Environment.class).toInstance(environment);
+
+ // Bind factory for creating UserContexts
+ install(new FactoryModuleBuilder()
+ .implement(UserContext.class, VaultUserContext.class)
+ .build(VaultUserContextFactory.class));
+
+ // Bind all other implementation-specific interfaces
+ configureVault();
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-vault/modules/guacamole-auth-vault-base/src/main/java/org/apache/guacamole/auth/vault/conf/VaultConfigurationService.java b/extensions/guacamole-auth-vault/modules/guacamole-auth-vault-base/src/main/java/org/apache/guacamole/auth/vault/conf/VaultConfigurationService.java
new file mode 100644
index 000000000..9cafbd45f
--- /dev/null
+++ b/extensions/guacamole-auth-vault/modules/guacamole-auth-vault-base/src/main/java/org/apache/guacamole/auth/vault/conf/VaultConfigurationService.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.auth.vault.conf;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.inject.Inject;
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.GuacamoleServerException;
+import org.apache.guacamole.auth.vault.VaultAuthenticationProviderModule;
+import org.apache.guacamole.environment.Environment;
+
+/**
+ * Base class for services which retrieve key vault configuration information.
+ * A concrete implementation of this class must be defined and bound for key
+ * vault support to work.
+ *
+ * @see VaultAuthenticationProviderModule
+ */
+public abstract class VaultConfigurationService {
+
+ /**
+ * The Guacamole server environment.
+ */
+ @Inject
+ private Environment environment;
+
+ /**
+ * ObjectMapper for deserializing JSON.
+ */
+ private static final ObjectMapper mapper = new ObjectMapper();
+
+ /**
+ * The name of the file containing a JSON mapping of Guacamole parameter
+ * token to vault secret name.
+ */
+ private final String tokenMappingFilename;
+
+ /**
+ * Creates a new VaultConfigurationService which retrieves the token/secret
+ * mapping from a JSON file having the given name.
+ *
+ * @param tokenMappingFilename
+ * The name of the JSON file containing the token/secret mapping.
+ */
+ protected VaultConfigurationService(String tokenMappingFilename) {
+ this.tokenMappingFilename = tokenMappingFilename;
+ }
+
+ /**
+ * Returns a mapping dictating the name of the secret which maps to each
+ * parameter token. In the returned mapping, the value of each entry is the
+ * name of the secret to use to populate the value of the parameter token,
+ * and the key of each entry is the name of the parameter token which
+ * should receive the value of the secret.
+ *
+ * The name of the secret may contain its own tokens, which will be
+ * substituted using values from the given filter. See the definition of
+ * VaultUserContext for the names of these tokens and the contexts in which
+ * they can be applied to secret names.
+ *
+ * @return
+ * A mapping dictating the name of the secret which maps to each
+ * parameter token.
+ *
+ * @throws GuacamoleException
+ * If the JSON file defining the token/secret mapping cannot be read.
+ */
+ public Map getTokenMapping() throws GuacamoleException {
+
+ // Get configuration file from GUACAMOLE_HOME
+ File confFile = new File(environment.getGuacamoleHome(), tokenMappingFilename);
+
+ // Deserialize token mapping from JSON
+ try {
+ return mapper.readValue(confFile, new TypeReference