You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by ra...@apache.org on 2026/09/11 08:56:20 UTC

(ranger) 30/34: RANGER-5716: Fix swapped client IP and resource in KMS Ranger audits (#1118)

This is an automated email from the ASF dual-hosted git repository.

ramackri pushed a commit to branch backport-audit-spiffe-2.10
in repository https://gitbox.apache.org/repos/asf/ranger.git

commit 7808aaf148f00de5e66970437f9c9be26c50cb15
Author: Ramachandran Krishnan <ra...@gmail.com>
AuthorDate: Fri Jul 31 07:39:14 2026 +0530

    RANGER-5716: Fix swapped client IP and resource in KMS Ranger audits (#1118)
    
    Pass the HTTP client address and key name to the correct assertAccess
    overload for invalidate cache and reencrypt operations so Ranger audit
    records show the real client IP and key resource instead of swapping them.
    
    Co-authored-by: ramk <ra...@cloudera.com>
    (cherry picked from commit b4fd13c20be154e7fc0b1377f16ea5b5c1327e12)
---
 .../apache/hadoop/crypto/key/kms/server/KMS.java   | 1067 ++++++++++---------
 .../hadoop/crypto/key/kms/server/TestKMS.java      | 1099 +++++++-------------
 2 files changed, 924 insertions(+), 1242 deletions(-)

diff --git a/kms/src/main/java/org/apache/hadoop/crypto/key/kms/server/KMS.java b/kms/src/main/java/org/apache/hadoop/crypto/key/kms/server/KMS.java
index cab5bbd2d..424e89aa7 100644
--- a/kms/src/main/java/org/apache/hadoop/crypto/key/kms/server/KMS.java
+++ b/kms/src/main/java/org/apache/hadoop/crypto/key/kms/server/KMS.java
@@ -6,9 +6,9 @@
  * 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
- *
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
  * 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.
@@ -17,29 +17,35 @@
  */
 package org.apache.hadoop.crypto.key.kms.server;
 
-import org.apache.hadoop.thirdparty.com.google.common.base.Preconditions;
-import org.apache.hadoop.thirdparty.com.google.common.base.Stopwatch;
-import org.apache.hadoop.util.KMSUtil;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.hadoop.classification.InterfaceAudience;
 import org.apache.hadoop.crypto.key.KeyProvider;
 import org.apache.hadoop.crypto.key.KeyProvider.KeyVersion;
 import org.apache.hadoop.crypto.key.KeyProviderCryptoExtension;
 import org.apache.hadoop.crypto.key.KeyProviderCryptoExtension.EncryptedKeyVersion;
+import org.apache.hadoop.crypto.key.kms.KMSClientProvider.KMSEncryptedKeyVersion;
+import org.apache.hadoop.crypto.key.kms.KMSClientProvider.KMSKeyVersion;
 import org.apache.hadoop.crypto.key.kms.KMSRESTConstants;
+import org.apache.hadoop.crypto.key.kms.server.KMSACLsType.Type;
 import org.apache.hadoop.security.AccessControlException;
 import org.apache.hadoop.security.UserGroupInformation;
-import org.apache.hadoop.crypto.key.kms.KMSClientProvider.KMSKeyVersion;
-import org.apache.hadoop.crypto.key.kms.KMSClientProvider.KMSEncryptedKeyVersion;
-import org.apache.hadoop.crypto.key.kms.server.KMSACLsType.Type;
 import org.apache.hadoop.security.token.delegation.web.HttpUserGroupInformation;
-import javax.ws.rs.core.UriBuilder;
+import org.apache.hadoop.thirdparty.com.google.common.base.Preconditions;
+import org.apache.hadoop.thirdparty.com.google.common.base.Stopwatch;
+import org.apache.hadoop.util.KMSUtil;
+import org.apache.ranger.kms.metrics.KMSMetricWrapper;
+import org.apache.ranger.kms.metrics.KMSMetrics;
+import org.apache.ranger.kms.metrics.collector.KMSMetricsCollector;
+import org.apache.ranger.kms.metrics.collector.KMSMetricsCollector.APIMetric;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.DefaultValue;
 import javax.ws.rs.GET;
+import javax.ws.rs.OPTIONS;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
@@ -48,6 +54,7 @@
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
 
 import java.io.IOException;
 import java.net.URI;
@@ -60,709 +67,737 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import org.apache.ranger.kms.metrics.KMSMetricWrapper;
-import org.apache.ranger.kms.metrics.KMSMetrics;
-import org.apache.ranger.kms.metrics.collector.KMSMetricsCollector;
-import org.apache.ranger.kms.metrics.collector.KMSMetricsCollector.APIMetric;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import static org.apache.hadoop.util.KMSUtil.checkNotEmpty;
 import static org.apache.hadoop.util.KMSUtil.checkNotNull;
+
 /**
  * Class providing the REST bindings, via Jersey, for the KMS.
  */
 @Path(KMSRESTConstants.SERVICE_VERSION)
 @InterfaceAudience.Private
 public class KMS {
-  static final Logger LOG = LoggerFactory.getLogger(KMS.class);
+    static final Logger LOG = LoggerFactory.getLogger(KMS.class);
 
-  private static final String KEY_NAME_VALIDATION = "[a-z,A-Z,0-9](?!.*--)(?!.*__)(?!.*-_)(?!.*_-)[\\w\\-\\_]*";
-  private static final int    MAX_NUM_PER_BATCH   = 10000;
+    private static final String KEY_NAME_VALIDATION     = "[a-z,A-Z,0-9](?!.*--)(?!.*__)(?!.*-_)(?!.*_-)[\\w\\-\\_]*";
+    private static final int    MAX_NUM_PER_BATCH       = 10000;
+    private static final String GENERATE_DEK_PATH_CONST = "_dek";
+    private static final int    DEFAULT_KEY_SIZE        = 256;
 
-  private final static String GENERATE_DEK_PATH_CONST = "_dek";
+    private final KeyProviderCryptoExtension provider;
+    private final KMSAudit                   kmsAudit;
+    private final KMSMetricsCollector        kmsMetricsCollector;
 
-  public enum KMSOp {
-    CREATE_KEY, DELETE_KEY, ROLL_NEW_VERSION, INVALIDATE_CACHE,
-    GET_KEYS, GET_KEYS_METADATA,
-    GET_KEY_VERSIONS, GET_METADATA, GET_KEY_VERSION, GET_CURRENT_KEY,
-    GENERATE_EEK, DECRYPT_EEK, REENCRYPT_EEK, REENCRYPT_EEK_BATCH
-  }
-
-
-  private final KeyProviderCryptoExtension provider;
-  private final KMSAudit                   kmsAudit;
+    public KMS() throws Exception {
+        this.provider            = KMSWebApp.getKeyProvider();
+        this.kmsAudit            = KMSWebApp.getKMSAudit();
+        this.kmsMetricsCollector = KMSMetricWrapper.getInstance(KMSWebApp.isMetricCollectionThreadSafe()).getKmsMetricsCollector();
+    }
 
-  private KMSMetricsCollector kmsMetricsCollector;
+    @POST
+    @Path(KMSRESTConstants.KEYS_RESOURCE)
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    @SuppressWarnings("unchecked")
+    public Response createKey(Map jsonKey, @Context HttpServletRequest request) throws Exception {
+        LOG.debug("==> createKey()");
 
-  public KMS() throws Exception {
-    provider = KMSWebApp.getKeyProvider();
-    kmsAudit = KMSWebApp.getKMSAudit();
-    this.kmsMetricsCollector = KMSMetricWrapper.getInstance(KMSWebApp.isMetricCollectionThreadSafe()).getKmsMetricsCollector();
-  }
+        try (APIMetric apiMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.KEY_CREATE_COUNT, KMSMetrics.KMSMetric.KEY_CREATE_ELAPSED_TIME)) {
+            KMSWebApp.getAdminCallsMeter().mark();
 
-  @POST
-  @Path(KMSRESTConstants.KEYS_RESOURCE)
-  @Consumes(MediaType.APPLICATION_JSON)
-  @Produces(MediaType.APPLICATION_JSON)
-  @SuppressWarnings("unchecked")
-  public Response createKey(Map jsonKey, @Context HttpServletRequest request) throws Exception {
-    LOG.debug("==> createKey()");
+            final UserGroupInformation user = HttpUserGroupInformation.get();
+            final String               name = (String) jsonKey.get(KMSRESTConstants.NAME_FIELD);
 
-    try (APIMetric apiMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.KEY_CREATE_COUNT, KMSMetrics.KMSMetric.KEY_CREATE_ELAPSED_TIME)) {
-      KMSWebApp.getAdminCallsMeter().mark();
+            checkNotEmpty(name, KMSRESTConstants.NAME_FIELD);
 
-      final UserGroupInformation user = HttpUserGroupInformation.get();
-      final String               name = (String) jsonKey.get(KMSRESTConstants.NAME_FIELD);
+            validateKeyName(name);
 
-      checkNotEmpty(name, KMSRESTConstants.NAME_FIELD);
+            assertAccess(Type.CREATE, user, KMSOp.CREATE_KEY, name, getClientIp(request));
 
-      validateKeyName(name);
+            final String cipher      = (String) jsonKey.get(KMSRESTConstants.CIPHER_FIELD);
+            final String material    = (String) jsonKey.get(KMSRESTConstants.MATERIAL_FIELD);
+            final int    length      = (jsonKey.containsKey(KMSRESTConstants.LENGTH_FIELD)) ? (Integer) jsonKey.get(KMSRESTConstants.LENGTH_FIELD) : DEFAULT_KEY_SIZE;
+            final String description = (String) jsonKey.get(KMSRESTConstants.DESCRIPTION_FIELD);
 
-      assertAccess(Type.CREATE, user, KMSOp.CREATE_KEY, name, getClientIp(request));
+            LOG.debug("Creating key: name={}, cipher={}, keyLength={}, description={}", name, cipher, length, description);
 
-      final String cipher      = (String) jsonKey.get(KMSRESTConstants.CIPHER_FIELD);
-      final String material    = (String) jsonKey.get(KMSRESTConstants.MATERIAL_FIELD);
-      final int    length      = (jsonKey.containsKey(KMSRESTConstants.LENGTH_FIELD)) ? (Integer) jsonKey.get(KMSRESTConstants.LENGTH_FIELD) : 0;
-      final String description = (String) jsonKey.get(KMSRESTConstants.DESCRIPTION_FIELD);
+            Map<String, String> attributes = (Map<String, String>) jsonKey.get(KMSRESTConstants.ATTRIBUTES_FIELD);
 
-      LOG.debug("Creating key: name={}, cipher={}, keyLength={}, description={}", name, cipher, length, description);
+            if (material != null) {
+                assertAccess(Type.SET_KEY_MATERIAL, user, KMSOp.CREATE_KEY, name, getClientIp(request));
+            }
 
-      Map<String, String> attributes = (Map<String, String>) jsonKey.get(KMSRESTConstants.ATTRIBUTES_FIELD);
+            final KeyProvider.Options options = new KeyProvider.Options(KMSWebApp.getConfiguration());
 
-      if (material != null) {
-        assertAccess(Type.SET_KEY_MATERIAL, user, KMSOp.CREATE_KEY, name, getClientIp(request));
-      }
+            if (cipher != null) {
+                options.setCipher(cipher);
+            }
 
-      final KeyProvider.Options options = new KeyProvider.Options(KMSWebApp.getConfiguration());
+            if (length != 0) {
+                options.setBitLength(length);
+            }
 
-      if (cipher != null) {
-        options.setCipher(cipher);
-      }
+            options.setDescription(description);
+            options.setAttributes(attributes);
 
-      if (length != 0) {
-        options.setBitLength(length);
-      }
+            KeyVersion keyVersion = user.doAs((PrivilegedExceptionAction<KeyVersion>) () -> {
+                final KeyVersion ret;
 
-      options.setDescription(description);
-      options.setAttributes(attributes);
+                if (material != null) {
+                    ret = provider.createKey(name, Base64.decodeBase64(material), options);
+                } else {
+                    ret = provider.createKey(name, options);
+                }
 
-      KeyVersion keyVersion = user.doAs((PrivilegedExceptionAction<KeyVersion>) () -> {
-        final KeyVersion ret;
+                provider.flush();
 
-        if (material != null) {
-          ret = provider.createKey(name, Base64.decodeBase64(material), options);
-        } else {
-          ret = provider.createKey(name, options);
-        }
+                return ret;
+            });
 
-        provider.flush();
+            kmsAudit.ok(user, KMSOp.CREATE_KEY, name, "UserProvidedMaterial:" + (material != null) + " Description:" + description);
 
-        return ret;
-      });
+            if (!KMSWebApp.getACLs().hasAccess(Type.GET, user, getClientIp(request))) {
+                keyVersion = removeKeyMaterial(keyVersion);
+            }
 
-      kmsAudit.ok(user, KMSOp.CREATE_KEY, name, "UserProvidedMaterial:" + (material != null) + " Description:" + description);
+            Map    json       = KMSUtil.toJSON(keyVersion);
+            String requestURL = KMSMDCFilter.getURL();
+            int    idx        = requestURL.lastIndexOf(KMSRESTConstants.KEYS_RESOURCE);
 
-      if (!KMSWebApp.getACLs().hasAccess(Type.GET, user, getClientIp(request))) {
-        keyVersion = removeKeyMaterial(keyVersion);
-      }
+            requestURL = requestURL.substring(0, idx);
+            URI locationURI = getKeyURI(requestURL, name);
 
-      Map    json       = KMSUtil.toJSON(keyVersion);
-      String requestURL = KMSMDCFilter.getURL();
-      int    idx        = requestURL.lastIndexOf(KMSRESTConstants.KEYS_RESOURCE);
+            Response response = Response.created(locationURI)
+                    .type(MediaType.APPLICATION_JSON)
+                    .entity(json)
+                    .build();
+            return response;
+        } catch (Exception e) {
+            LOG.error("Exception in createKey.", e);
 
-      requestURL = requestURL.substring(0, idx);
+            throw e;
+        } finally {
+            LOG.debug("<== createKey()");
+        }
+    }
 
-      return Response.created(getKeyURI(KMSRESTConstants.SERVICE_VERSION, name)).type(MediaType.APPLICATION_JSON).header("Location", getKeyURI(requestURL, name)).entity(json).build();
-    } catch (Exception e) {
-      LOG.error("Exception in createKey.", e);
-      throw e;
-    } finally {
-        LOG.debug("<== createKey()");
+    /**
+     * Handles OPTIONS requests for the root v1 resource (e.g., /kms/v1/).
+     * This is required for the Kerberos/SPNEGO authentication handshake.
+     */
+    @OPTIONS
+    public Response getOptions() {
+        return Response.ok().build();
     }
-  }
 
-  @DELETE
-  @Path(KMSRESTConstants.KEY_RESOURCE + "/{name:.*}")
-  public Response deleteKey(@PathParam("name") final String name, @Context HttpServletRequest request) throws Exception {
-    LOG.debug("==> deleteKey({})", name);
+    @DELETE
+    @Path(KMSRESTConstants.KEY_RESOURCE + "/{name:.*}")
+    public Response deleteKey(@PathParam("name") final String name, @Context HttpServletRequest request) throws Exception {
+        LOG.debug("==> deleteKey({})", name);
 
-    try (APIMetric apiMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.DELETE_KEY_COUNT, KMSMetrics.KMSMetric.DELETE_KEY_ELAPSED_TIME)) {
-      KMSWebApp.getAdminCallsMeter().mark();
+        try (APIMetric apiMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.DELETE_KEY_COUNT, KMSMetrics.KMSMetric.DELETE_KEY_ELAPSED_TIME)) {
+            KMSWebApp.getAdminCallsMeter().mark();
 
-      UserGroupInformation user = HttpUserGroupInformation.get();
+            UserGroupInformation user = HttpUserGroupInformation.get();
 
-      assertAccess(Type.DELETE, user, KMSOp.DELETE_KEY, name, getClientIp(request));
+            assertAccess(Type.DELETE, user, KMSOp.DELETE_KEY, name, getClientIp(request));
 
-      checkNotEmpty(name, "name");
+            checkNotEmpty(name, "name");
 
-      user.doAs((PrivilegedExceptionAction<Void>) () -> {
-        provider.deleteKey(name);
+            user.doAs((PrivilegedExceptionAction<Void>) () -> {
+                provider.deleteKey(name);
 
-        provider.flush();
+                provider.flush();
 
-        return null;
-      });
+                return null;
+            });
 
-      kmsAudit.ok(user, KMSOp.DELETE_KEY, name, "");
+            kmsAudit.ok(user, KMSOp.DELETE_KEY, name, "");
 
-      return Response.ok().build();
-    } catch (Exception e) {
-      LOG.error("Exception in deleteKey.", e);
-      throw e;
-    } finally {
-      LOG.debug("<== deleteKey({})", name);
+            return Response.ok().build();
+        } catch (Exception e) {
+            LOG.error("Exception in deleteKey.", e);
+
+            throw e;
+        } finally {
+            LOG.debug("<== deleteKey({})", name);
+        }
     }
-  }
 
-  @POST
-  @Path(KMSRESTConstants.KEY_RESOURCE + "/{name:.*}")
-  @Consumes(MediaType.APPLICATION_JSON)
-  @Produces(MediaType.APPLICATION_JSON)
-  public Response rolloverKey(@PathParam("name") final String name, Map jsonMaterial, @Context HttpServletRequest request) throws Exception {
-    LOG.debug("==> rolloverKey({})", name);
+    @POST
+    @Path(KMSRESTConstants.KEY_RESOURCE + "/{name:.*}")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response rolloverKey(@PathParam("name") final String name, Map jsonMaterial, @Context HttpServletRequest request) throws Exception {
+        LOG.debug("==> rolloverKey({})", name);
 
-    try (APIMetric apiMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.ROLL_NEW_VERSION_COUNT, KMSMetrics.KMSMetric.ROLL_NEW_VERSION_ELAPSED_TIME)) {
-      KMSWebApp.getAdminCallsMeter().mark();
+        try (APIMetric apiMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.ROLL_NEW_VERSION_COUNT, KMSMetrics.KMSMetric.ROLL_NEW_VERSION_ELAPSED_TIME)) {
+            KMSWebApp.getAdminCallsMeter().mark();
 
-      UserGroupInformation user = HttpUserGroupInformation.get();
+            UserGroupInformation user = HttpUserGroupInformation.get();
 
-      assertAccess(Type.ROLLOVER, user, KMSOp.ROLL_NEW_VERSION, name, getClientIp(request));
+            assertAccess(Type.ROLLOVER, user, KMSOp.ROLL_NEW_VERSION, name, getClientIp(request));
 
-      checkNotEmpty(name, "name");
+            checkNotEmpty(name, "name");
 
-      final String material = (String) jsonMaterial.get(KMSRESTConstants.MATERIAL_FIELD);
+            final String material = (String) jsonMaterial.get(KMSRESTConstants.MATERIAL_FIELD);
 
-      if (material != null) {
-        assertAccess(Type.SET_KEY_MATERIAL, user, KMSOp.ROLL_NEW_VERSION, name, getClientIp(request));
-      }
+            if (material != null) {
+                assertAccess(Type.SET_KEY_MATERIAL, user, KMSOp.ROLL_NEW_VERSION, name, getClientIp(request));
+            }
 
-      KeyVersion keyVersion = user.doAs((PrivilegedExceptionAction<KeyVersion>) () -> {
-        final KeyVersion ret;
+            KeyVersion keyVersion = user.doAs((PrivilegedExceptionAction<KeyVersion>) () -> {
+                final KeyVersion ret;
 
-        if (material != null) {
-          ret = provider.rollNewVersion(name, Base64.decodeBase64(material));
-        } else {
-          ret = provider.rollNewVersion(name);
-        }
+                if (material != null) {
+                    ret = provider.rollNewVersion(name, Base64.decodeBase64(material));
+                } else {
+                    ret = provider.rollNewVersion(name);
+                }
 
-        provider.flush();
+                provider.flush();
 
-        return ret;
-      });
+                return ret;
+            });
 
-      kmsAudit.ok(user, KMSOp.ROLL_NEW_VERSION, name, "UserProvidedMaterial:" + (material != null) + " NewVersion:" + keyVersion.getVersionName());
+            kmsAudit.ok(user, KMSOp.ROLL_NEW_VERSION, name, "UserProvidedMaterial:" + (material != null) + " NewVersion:" + keyVersion.getVersionName());
 
-      if (!KMSWebApp.getACLs().hasAccess(Type.GET, user, getClientIp(request))) {
-        keyVersion = removeKeyMaterial(keyVersion);
-      }
+            if (!KMSWebApp.getACLs().hasAccess(Type.GET, user, getClientIp(request))) {
+                keyVersion = removeKeyMaterial(keyVersion);
+            }
 
-      Map json = KMSUtil.toJSON(keyVersion);
+            Map json = KMSUtil.toJSON(keyVersion);
 
-      return Response.ok().type(MediaType.APPLICATION_JSON).entity(json).build();
-    } catch (Exception e) {
-      LOG.error("Exception in rolloverKey.", e);
-      throw e;
-    } finally {
-      LOG.debug("<== rolloverKey({})", name);
+            return Response.ok().type(MediaType.APPLICATION_JSON).entity(json).build();
+        } catch (Exception e) {
+            LOG.error("Exception in rolloverKey.", e);
+
+            throw e;
+        } finally {
+            LOG.debug("<== rolloverKey({})", name);
+        }
     }
-  }
 
-  @POST
-  @Path(KMSRESTConstants.KEY_RESOURCE + "/{name:.*}/" + KMSRESTConstants.INVALIDATECACHE_RESOURCE)
-  public Response invalidateCache(@PathParam("name") final String name, @Context HttpServletRequest request) throws Exception {
-    LOG.debug("==> invalidateCache({})", name);
+    @POST
+    @Path(KMSRESTConstants.KEY_RESOURCE + "/{name:.*}/" + KMSRESTConstants.INVALIDATECACHE_RESOURCE)
+    public Response invalidateCache(@PathParam("name") final String name, @Context HttpServletRequest request) throws Exception {
+        LOG.debug("==> invalidateCache({})", name);
 
-    try (APIMetric apiMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.INVALIDATE_CACHE_COUNT, KMSMetrics.KMSMetric.INVALIDATE_CACHE_ELAPSED_TIME)) {
-      KMSWebApp.getAdminCallsMeter().mark();
+        try (APIMetric apiMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.INVALIDATE_CACHE_COUNT, KMSMetrics.KMSMetric.INVALIDATE_CACHE_ELAPSED_TIME)) {
+            KMSWebApp.getAdminCallsMeter().mark();
 
-      checkNotEmpty(name, "name");
+            checkNotEmpty(name, "name");
 
-      UserGroupInformation user = HttpUserGroupInformation.get();
+            UserGroupInformation user = HttpUserGroupInformation.get();
 
-      assertAccess(Type.ROLLOVER, user, KMSOp.INVALIDATE_CACHE, name, getClientIp(request));
+            assertAccess(Type.ROLLOVER, user, KMSOp.INVALIDATE_CACHE, name, getClientIp(request));
 
-      user.doAs((PrivilegedExceptionAction<Void>) () -> {
-        provider.invalidateCache(name);
+            user.doAs((PrivilegedExceptionAction<Void>) () -> {
+                provider.invalidateCache(name);
 
-        provider.flush();
+                provider.flush();
 
-        return null;
-      });
+                return null;
+            });
 
-      kmsAudit.ok(user, KMSOp.INVALIDATE_CACHE, name, "");
+            kmsAudit.ok(user, KMSOp.INVALIDATE_CACHE, name, "");
+
+            return Response.ok().build();
+        } catch (Exception e) {
+            LOG.error("Exception in invalidateCache for key name {}.", name, e);
 
-      return Response.ok().build();
-    } catch (Exception e) {
-      LOG.error("Exception in invalidateCache for key name {}.", name, e);
-      throw e;
-    } finally {
-      LOG.debug("<== invalidateCache({})", name);
+            throw e;
+        } finally {
+            LOG.debug("<== invalidateCache({})", name);
+        }
     }
-  }
 
-  @GET
-  @Path(KMSRESTConstants.KEYS_METADATA_RESOURCE)
-  @Produces(MediaType.APPLICATION_JSON)
-  public Response getKeysMetadata(@QueryParam(KMSRESTConstants.KEY) List<String> keyNamesList, @Context HttpServletRequest request) throws Exception {
-    LOG.debug("==> getKeysMetadata()");
+    @GET
+    @Path(KMSRESTConstants.KEYS_METADATA_RESOURCE)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getKeysMetadata(@QueryParam(KMSRESTConstants.KEY) List<String> keyNamesList, @Context HttpServletRequest request) throws Exception {
+        LOG.debug("==> getKeysMetadata()");
+
+        try (APIMetric apiMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.GET_KEYS_METADATA_COUNT, KMSMetrics.KMSMetric.GET_KEYS_METADATA_ELAPSED_TIME)) {
+            KMSWebApp.getAdminCallsMeter().mark();
+
+            final UserGroupInformation user     = HttpUserGroupInformation.get();
+            final String[]             keyNames = keyNamesList.toArray(new String[0]);
 
-    try (APIMetric apiMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.GET_KEYS_METADATA_COUNT, KMSMetrics.KMSMetric.GET_KEYS_METADATA_ELAPSED_TIME)) {
-      KMSWebApp.getAdminCallsMeter().mark();
+            assertAccess(Type.GET_METADATA, user, KMSOp.GET_KEYS_METADATA, getClientIp(request));
 
-      final UserGroupInformation user     = HttpUserGroupInformation.get();
-      final String[]             keyNames = keyNamesList.toArray(new String[0]);
+            KeyProvider.Metadata[] keysMeta = user.doAs((PrivilegedExceptionAction<KeyProvider.Metadata[]>) () -> provider.getKeysMetadata(keyNames));
+            Object                 json     = KMSServerJSONUtils.toJSON(keyNames, keysMeta);
 
-      assertAccess(Type.GET_METADATA, user, KMSOp.GET_KEYS_METADATA, getClientIp(request));
+            this.kmsMetricsCollector.updateMetric(KMSMetrics.KMSMetric.GET_KEYS_METADATA_KEYNAMES_COUNT, keyNames.length);
 
-      KeyProvider.Metadata[] keysMeta = user.doAs((PrivilegedExceptionAction<KeyProvider.Metadata[]>) () -> provider.getKeysMetadata(keyNames));
-      Object                 json     = KMSServerJSONUtils.toJSON(keyNames, keysMeta);
-      this.kmsMetricsCollector.updateMetric(KMSMetrics.KMSMetric.GET_KEYS_METADATA_KEYNAMES_COUNT, keyNames.length);
+            kmsAudit.ok(user, KMSOp.GET_KEYS_METADATA, "");
 
-      kmsAudit.ok(user, KMSOp.GET_KEYS_METADATA, "");
+            return Response.ok().type(MediaType.APPLICATION_JSON).entity(json).build();
+        } catch (Exception e) {
+            LOG.error("Exception in getKeysmetadata.", e);
 
-      return Response.ok().type(MediaType.APPLICATION_JSON).entity(json).build();
-    } catch (Exception e) {
-      LOG.error("Exception in getKeysMetadata.", e);
-      throw e;
-    } finally {
-      LOG.debug("<== getKeysMetadata()");
+            throw e;
+        } finally {
+            LOG.debug("<== getKeysMetadata()");
+        }
     }
-  }
 
-  @GET
-  @Path(KMSRESTConstants.KEYS_NAMES_RESOURCE)
-  @Produces(MediaType.APPLICATION_JSON)
-  public Response getKeyNames(@Context HttpServletRequest request) throws Exception {
-    LOG.debug("==> getKeyNames()");
+    @GET
+    @Path(KMSRESTConstants.KEYS_NAMES_RESOURCE)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getKeyNames(@Context HttpServletRequest request) throws Exception {
+        LOG.debug("==> getKeyNames()");
 
-    try (APIMetric apiMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.GET_KEYS_COUNT, KMSMetrics.KMSMetric.GET_KEYS_ELAPSED_TIME)) {
-      KMSWebApp.getAdminCallsMeter().mark();
+        try (APIMetric apiMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.GET_KEYS_COUNT, KMSMetrics.KMSMetric.GET_KEYS_ELAPSED_TIME)) {
+            KMSWebApp.getAdminCallsMeter().mark();
 
-      UserGroupInformation user = HttpUserGroupInformation.get();
+            UserGroupInformation user = HttpUserGroupInformation.get();
 
-      assertAccess(Type.GET_KEYS, user, KMSOp.GET_KEYS, getClientIp(request));
+            assertAccess(Type.GET_KEYS, user, KMSOp.GET_KEYS, getClientIp(request));
 
-      List<String> json = user.doAs((PrivilegedExceptionAction<List<String>>) provider::getKeys);
+            List<String> json = user.doAs((PrivilegedExceptionAction<List<String>>) provider::getKeys);
 
-      kmsAudit.ok(user, KMSOp.GET_KEYS, "");
+            kmsAudit.ok(user, KMSOp.GET_KEYS, "");
+
+            return Response.ok().type(MediaType.APPLICATION_JSON).entity(json).build();
+        } catch (Exception e) {
+            LOG.error("Exception in getkeyNames.", e);
 
-      return Response.ok().type(MediaType.APPLICATION_JSON).entity(json).build();
-    } catch (Exception e) {
-      LOG.error("Exception in getkeyNames.", e);
-      throw e;
-    } finally {
-      LOG.debug("<== getKeyNames()");
+            throw e;
+        } finally {
+            LOG.debug("<== getKeyNames()");
+        }
     }
-  }
 
-  @GET
-  @Path(KMSRESTConstants.KEY_RESOURCE + "/{name:.*}")
-  public Response getKey(@PathParam("name") String name, @Context HttpServletRequest request) throws Exception {
-    LOG.debug("==> getKey({})", name);
+    @GET
+    @Path(KMSRESTConstants.KEY_RESOURCE + "/{name:.*}")
+    public Response getKey(@PathParam("name") String name, @Context HttpServletRequest request) throws Exception {
+        LOG.debug("==> getKey({})", name);
 
-    try {
-      return getMetadata(name, request);
-    } catch (Exception e) {
-      LOG.error("Exception in getKey.", e);
+        try {
+            return getMetadata(name, request);
+        } catch (Exception e) {
+            LOG.error("Exception in getKey.", e);
 
-      throw e;
-    } finally {
-      LOG.debug("<== getKey({})", name);
+            throw e;
+        } finally {
+            LOG.debug("<== getKey({})", name);
+        }
     }
-  }
 
-  @GET
-  @Path(KMSRESTConstants.KEY_RESOURCE + "/{name:.*}/" + KMSRESTConstants.METADATA_SUB_RESOURCE)
-  @Produces(MediaType.APPLICATION_JSON)
-  public Response getMetadata(@PathParam("name") final String name, @Context HttpServletRequest request) throws Exception {
-    LOG.debug("==> getMetadata({})", name);
+    @GET
+    @Path(KMSRESTConstants.KEY_RESOURCE + "/{name:.*}/" + KMSRESTConstants.METADATA_SUB_RESOURCE)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getMetadata(@PathParam("name") final String name, @Context HttpServletRequest request) throws Exception {
+        LOG.debug("==> getMetadata({})", name);
+
+        try (APIMetric apiMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.GET_METADATA_COUNT, KMSMetrics.KMSMetric.GET_METADATA_ELAPSED_TIME)) {
+            KMSWebApp.getAdminCallsMeter().mark();
 
-    try (APIMetric apiMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.GET_METADATA_COUNT, KMSMetrics.KMSMetric.GET_METADATA_ELAPSED_TIME)) {
-      KMSWebApp.getAdminCallsMeter().mark();
-      UserGroupInformation user = HttpUserGroupInformation.get();
+            UserGroupInformation user = HttpUserGroupInformation.get();
 
-      checkNotEmpty(name, "name");
+            checkNotEmpty(name, "name");
 
-      assertAccess(Type.GET_METADATA, user, KMSOp.GET_METADATA, name, getClientIp(request));
+            assertAccess(Type.GET_METADATA, user, KMSOp.GET_METADATA, name, getClientIp(request));
 
-      KeyProvider.Metadata metadata = user.doAs((PrivilegedExceptionAction<KeyProvider.Metadata>) () -> provider.getMetadata(name));
-      Object               json     = KMSServerJSONUtils.toJSON(name, metadata);
+            KeyProvider.Metadata metadata = user.doAs((PrivilegedExceptionAction<KeyProvider.Metadata>) () -> provider.getMetadata(name));
+            Object               json     = KMSServerJSONUtils.toJSON(name, metadata);
 
-      kmsAudit.ok(user, KMSOp.GET_METADATA, name, "");
+            kmsAudit.ok(user, KMSOp.GET_METADATA, name, "");
+
+            return Response.ok().type(MediaType.APPLICATION_JSON).entity(json).build();
+        } catch (Exception e) {
+            LOG.error("Exception in getMetadata.", e);
 
-      return Response.ok().type(MediaType.APPLICATION_JSON).entity(json).build();
-    } catch (Exception e) {
-      LOG.error("Exception in getMetadata.", e);
-      throw e;
-    } finally {
-      LOG.debug("<== getMetadata({})", name);
+            throw e;
+        } finally {
+            LOG.debug("<== getMetadata({})", name);
+        }
     }
-  }
 
-  @GET
-  @Path(KMSRESTConstants.KEY_RESOURCE + "/{name:.*}/" + KMSRESTConstants.CURRENT_VERSION_SUB_RESOURCE)
-  @Produces(MediaType.APPLICATION_JSON)
-  public Response getCurrentVersion(@PathParam("name") final String name, @Context HttpServletRequest request) throws Exception {
-    LOG.debug("==> getCurrentVersion({})", name);
+    @GET
+    @Path(KMSRESTConstants.KEY_RESOURCE + "/{name:.*}/" + KMSRESTConstants.CURRENT_VERSION_SUB_RESOURCE)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getCurrentVersion(@PathParam("name") final String name, @Context HttpServletRequest request) throws Exception {
+        LOG.debug("==> getCurrentVersion({})", name);
+
+        try (APIMetric apiMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.GET_CURRENT_KEY_COUNT, KMSMetrics.KMSMetric.GET_CURRENT_KEY_ELAPSED_TIME)) {
+            KMSWebApp.getKeyCallsMeter().mark();
 
-    try (APIMetric apiMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.GET_CURRENT_KEY_COUNT, KMSMetrics.KMSMetric.GET_CURRENT_KEY_ELAPSED_TIME)) {
-      KMSWebApp.getKeyCallsMeter().mark();
-      UserGroupInformation user = HttpUserGroupInformation.get();
+            UserGroupInformation user = HttpUserGroupInformation.get();
 
-      checkNotEmpty(name, "name");
+            checkNotEmpty(name, "name");
 
-      assertAccess(Type.GET, user, KMSOp.GET_CURRENT_KEY, name, getClientIp(request));
+            assertAccess(Type.GET, user, KMSOp.GET_CURRENT_KEY, name, getClientIp(request));
 
-      KeyVersion keyVersion = user.doAs((PrivilegedExceptionAction<KeyVersion>) () -> provider.getCurrentKey(name));
+            KeyVersion keyVersion = user.doAs((PrivilegedExceptionAction<KeyVersion>) () -> provider.getCurrentKey(name));
+            Object     json       = KMSUtil.toJSON(keyVersion);
 
-      Object json = KMSUtil.toJSON(keyVersion);
+            kmsAudit.ok(user, KMSOp.GET_CURRENT_KEY, name, "");
 
-      kmsAudit.ok(user, KMSOp.GET_CURRENT_KEY, name, "");
+            return Response.ok().type(MediaType.APPLICATION_JSON).entity(json).build();
+        } catch (Exception e) {
+            LOG.error("Exception in getCurrentVersion.", e);
 
-      return Response.ok().type(MediaType.APPLICATION_JSON).entity(json).build();
-    } catch (Exception e) {
-      LOG.error("Exception in getCurrentVersion.", e);
-      throw e;
-    } finally {
-      LOG.debug("<== getCurrentVersion({})", name);
+            throw e;
+        } finally {
+            LOG.debug("<== getCurrentVersion({})", name);
+        }
     }
-  }
 
-  @GET
-  @Path(KMSRESTConstants.KEY_VERSION_RESOURCE + "/{versionName:.*}")
-  @Produces(MediaType.APPLICATION_JSON)
-  public Response getKeyVersion(@PathParam("versionName") final String versionName, @Context HttpServletRequest request) throws Exception {
-    LOG.debug("==> getKeyVersion({})", versionName);
+    @GET
+    @Path(KMSRESTConstants.KEY_VERSION_RESOURCE + "/{versionName:.*}")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getKeyVersion(@PathParam("versionName") final String versionName, @Context HttpServletRequest request) throws Exception {
+        LOG.debug("==> getKeyVersion({})", versionName);
 
-    try (APIMetric apiMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.GET_KEY_VERSION_COUNT, KMSMetrics.KMSMetric.GET_KEY_VERSION_ELAPSED_TIME)) {
-      KMSWebApp.getKeyCallsMeter().mark();
-      UserGroupInformation user = HttpUserGroupInformation.get();
+        try (APIMetric apiMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.GET_KEY_VERSION_COUNT, KMSMetrics.KMSMetric.GET_KEY_VERSION_ELAPSED_TIME)) {
+            KMSWebApp.getKeyCallsMeter().mark();
 
-      checkNotEmpty(versionName, "versionName");
+            UserGroupInformation user = HttpUserGroupInformation.get();
 
-      assertAccess(Type.GET, user, KMSOp.GET_KEY_VERSION, KeyProvider.getBaseName(versionName), getClientIp(request));
+            checkNotEmpty(versionName, "versionName");
 
-      KeyVersion keyVersion = user.doAs((PrivilegedExceptionAction<KeyVersion>) () -> provider.getKeyVersion(versionName));
+            assertAccess(Type.GET, user, KMSOp.GET_KEY_VERSION, getClientIp(request));
 
-      if (keyVersion != null) {
-        kmsAudit.ok(user, KMSOp.GET_KEY_VERSION, keyVersion.getName(), "");
-      }
+            KeyVersion keyVersion = user.doAs((PrivilegedExceptionAction<KeyVersion>) () -> provider.getKeyVersion(versionName));
 
-      Object json = KMSUtil.toJSON(keyVersion);
+            if (keyVersion != null) {
+                kmsAudit.ok(user, KMSOp.GET_KEY_VERSION, keyVersion.getName(), "");
+            }
 
-      return Response.ok().type(MediaType.APPLICATION_JSON).entity(json).build();
-    } catch (Exception e) {
-      LOG.error("Exception in getKeyVersion.", e);
-      throw e;
-    } finally {
-      LOG.debug("<== getKeyVersion({})", versionName);
-    }
-  }
-  @GET
-  @Path(KMSRESTConstants.KEY_RESOURCE + "/{name:.*}/" + GENERATE_DEK_PATH_CONST)
-  @Produces(MediaType.APPLICATION_JSON)
-  public Response generateDataKey(@PathParam("name") final String name, @Context HttpServletRequest request) throws Exception{
-    LOG.debug("==> generateDataKey(name={}", name);
-
-    try {
-      UserGroupInformation user = HttpUserGroupInformation.get();
-      checkNotEmpty(name, "name");
-
-      EncryptedKeyVersion encryptedKeyVersion = null;
-      try (APIMetric apiMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.EEK_GENERATE_COUNT, KMSMetrics.KMSMetric.EEK_GENERATE_ELAPSED_TIME)) {
-        assertAccess(Type.GENERATE_EEK, user, KMSOp.GENERATE_EEK, name, getClientIp(request));
-        encryptedKeyVersion = user.doAs((PrivilegedExceptionAction<EncryptedKeyVersion>) () -> provider.generateEncryptedKey(name));
-        kmsAudit.ok(user, KMSOp.GENERATE_EEK, name, "generateDataKey execution");
-      }
-
-      KeyVersion retKeyVersion = null;
-      try (APIMetric apiMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.EEK_DECRYPT_COUNT, KMSMetrics.KMSMetric.EEK_DECRYPT_ELAPSED_TIME)) {
-        assertAccess(Type.DECRYPT_EEK, user, KMSOp.DECRYPT_EEK, name, getClientIp(request));
-
-        EncryptedKeyVersion finalEncryptedKeyVersion = encryptedKeyVersion;
-        retKeyVersion = user.doAs((PrivilegedExceptionAction<KeyVersion>) () -> {
-          KMSEncryptedKeyVersion ekv = new KMSEncryptedKeyVersion(finalEncryptedKeyVersion.getEncryptionKeyName(), finalEncryptedKeyVersion.getEncryptionKeyVersionName(),
-                  finalEncryptedKeyVersion.getEncryptedKeyIv(), KeyProviderCryptoExtension.EEK, finalEncryptedKeyVersion.getEncryptedKeyVersion().getMaterial());
-
-          return provider.decryptEncryptedKey(ekv);
-        });
-        kmsAudit.ok(user, KMSOp.DECRYPT_EEK, name, "generateDataKey execution");
-      }
-
-      Map<String,Object> response = new HashMap<>();
-      response.put("edek", KMSUtil.toJSON(encryptedKeyVersion));
-      response.put("dek", KMSUtil.toJSON(retKeyVersion));
-
-      return Response.ok().type(MediaType.APPLICATION_JSON).entity(response).build();
-    } catch(Exception e){
-      LOG.error("Exception in generateDataKey:", e);
-      throw new IOException(e);
-    } finally {
-      LOG.debug("<== generateDataKey(name={}", name);
+            Object json = KMSUtil.toJSON(keyVersion);
+
+            return Response.ok().type(MediaType.APPLICATION_JSON).entity(json).build();
+        } catch (Exception e) {
+            LOG.error("Exception in getKeyVersion.", e);
+
+            throw e;
+        } finally {
+            LOG.debug("<== getKeyVersion({})", versionName);
+        }
     }
 
-  }
+    @GET
+    @Path(KMSRESTConstants.KEY_RESOURCE + "/{name:.*}/" + GENERATE_DEK_PATH_CONST)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response generateDataKey(@PathParam("name") final String name, @Context HttpServletRequest request) throws Exception {
+        LOG.debug("==> generateDataKey(name={}", name);
+
+        try {
+            UserGroupInformation user = HttpUserGroupInformation.get();
 
-  @SuppressWarnings({ "rawtypes", "unchecked" })
-  @GET
-  @Path(KMSRESTConstants.KEY_RESOURCE + "/{name:.*}/" + KMSRESTConstants.EEK_SUB_RESOURCE)
-  @Produces(MediaType.APPLICATION_JSON)
-  public Response generateEncryptedKeys(@PathParam("name") final String name,
-                                        @QueryParam(KMSRESTConstants.EEK_OP) String edekOp,
-                                        @DefaultValue("1") @QueryParam(KMSRESTConstants.EEK_NUM_KEYS) final int numKeys,
-                                        @Context HttpServletRequest request) throws Exception {
-    LOG.debug("==> generateEncryptedKeys(name={}, eekOp={}, numKeys={})", name, edekOp, numKeys);
+            checkNotEmpty(name, "name");
 
-    try (APIMetric apiElapsedMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.EEK_GENERATE_COUNT, KMSMetrics.KMSMetric.EEK_GENERATE_ELAPSED_TIME)) {
-      UserGroupInformation user = HttpUserGroupInformation.get();
+            EncryptedKeyVersion encryptedKeyVersion = null;
+            try (APIMetric apiMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.EEK_GENERATE_COUNT, KMSMetrics.KMSMetric.EEK_GENERATE_ELAPSED_TIME)) {
+                assertAccess(Type.GENERATE_EEK, user, KMSOp.GENERATE_EEK, name, getClientIp(request));
 
-      checkNotEmpty(name, "name");
+                encryptedKeyVersion = user.doAs((PrivilegedExceptionAction<EncryptedKeyVersion>) () -> provider.generateEncryptedKey(name));
+                kmsAudit.ok(user, KMSOp.GENERATE_EEK, name, "generateDataKey execution");
+            }
 
-      checkNotNull(edekOp, "eekOp");
+            KeyVersion retKeyVersion = null;
+            try (APIMetric apiMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.EEK_DECRYPT_COUNT, KMSMetrics.KMSMetric.EEK_DECRYPT_ELAPSED_TIME)) {
+                assertAccess(Type.DECRYPT_EEK, user, KMSOp.DECRYPT_EEK, name, getClientIp(request));
 
-      Object retJSON;
+                EncryptedKeyVersion finalEncryptedKeyVersion = encryptedKeyVersion;
+                retKeyVersion = user.doAs((PrivilegedExceptionAction<KeyVersion>) () -> {
+                    KMSEncryptedKeyVersion ekv = new KMSEncryptedKeyVersion(finalEncryptedKeyVersion.getEncryptionKeyName(), finalEncryptedKeyVersion.getEncryptionKeyVersionName(),
+                            finalEncryptedKeyVersion.getEncryptedKeyIv(), KeyProviderCryptoExtension.EEK, finalEncryptedKeyVersion.getEncryptedKeyVersion().getMaterial());
 
-      if (edekOp.equals(KMSRESTConstants.EEK_GENERATE)) {
-        final List<EncryptedKeyVersion> retEdeks = new LinkedList<>();
+                    return provider.decryptEncryptedKey(ekv);
+                });
 
-        try {
-          assertAccess(Type.GENERATE_EEK, user, KMSOp.GENERATE_EEK, name, getClientIp(request));
-          user.doAs((PrivilegedExceptionAction<Void>) () -> {
-            for (int i = 0; i < numKeys; i++) {
-              retEdeks.add(provider.generateEncryptedKey(name));
+                kmsAudit.ok(user, KMSOp.DECRYPT_EEK, name, "generateDataKey execution");
             }
 
-            return null;
-          });
+            Map<String, Object> response = new HashMap<>();
 
-          kmsAudit.ok(user, KMSOp.GENERATE_EEK, name, "");
-          retJSON = new ArrayList();
+            response.put("edek", KMSUtil.toJSON(encryptedKeyVersion));
+            response.put("dek", KMSUtil.toJSON(retKeyVersion));
 
-          for (EncryptedKeyVersion edek : retEdeks) {
-            ((ArrayList) retJSON).add(KMSUtil.toJSON(edek));
-          }
+            return Response.ok().type(MediaType.APPLICATION_JSON).entity(response).build();
         } catch (Exception e) {
-          LOG.error("Exception in generateEncryptedKeys:", e);
-          throw new IOException(e);
+            LOG.error("Exception in generateDataKey:", e);
+
+            throw e;
+        } finally {
+            LOG.debug("<== generateDataKey(name={}", name);
         }
-      } else {
-        StringBuilder error = new StringBuilder("IllegalArgumentException Wrong ");
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    @GET
+    @Path(KMSRESTConstants.KEY_RESOURCE + "/{name:.*}/" + KMSRESTConstants.EEK_SUB_RESOURCE)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response generateEncryptedKeys(@PathParam("name") final String name, @QueryParam(KMSRESTConstants.EEK_OP) String edekOp,
+            @DefaultValue("1") @QueryParam(KMSRESTConstants.EEK_NUM_KEYS) final int numKeys, @Context HttpServletRequest request) throws Exception {
+        LOG.debug("==> generateEncryptedKeys(name={}, eekOp={}, numKeys={})", name, edekOp, numKeys);
+
+        try (APIMetric apiElapsedMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.EEK_GENERATE_COUNT, KMSMetrics.KMSMetric.EEK_GENERATE_ELAPSED_TIME)) {
+            UserGroupInformation user = HttpUserGroupInformation.get();
+
+            checkNotEmpty(name, "name");
+
+            checkNotNull(edekOp, "eekOp");
+
+            Object retJSON;
+
+            if (edekOp.equals(KMSRESTConstants.EEK_GENERATE)) {
+                final List<EncryptedKeyVersion> retEdeks = new LinkedList<>();
+
+                assertAccess(Type.GENERATE_EEK, user, KMSOp.GENERATE_EEK, name, getClientIp(request));
+                try {
+                    user.doAs((PrivilegedExceptionAction<Void>) () -> {
+                        for (int i = 0; i < numKeys; i++) {
+                            retEdeks.add(provider.generateEncryptedKey(name));
+                        }
+
+                        return null;
+                    });
+
+                    kmsAudit.ok(user, KMSOp.GENERATE_EEK, name, "");
+
+                    retJSON = new ArrayList();
 
-        error.append(KMSRESTConstants.EEK_OP)
-             .append(" value, it must be ")
-             .append(KMSRESTConstants.EEK_GENERATE)
-             .append(" or ")
-             .append(KMSRESTConstants.EEK_DECRYPT);
+                    for (EncryptedKeyVersion edek : retEdeks) {
+                        ((ArrayList) retJSON).add(KMSUtil.toJSON(edek));
+                    }
+                } catch (Exception e) {
+                    LOG.error("Exception in generateEncryptedKeys:", e);
 
-        LOG.error(error.toString());
+                    throw new IOException(e);
+                }
+            } else {
+                StringBuilder error = new StringBuilder("IllegalArgumentException Wrong ");
 
-        throw new IllegalArgumentException(error.toString());
-      }
+                error.append(KMSRESTConstants.EEK_OP)
+                        .append(" value, it must be ")
+                        .append(KMSRESTConstants.EEK_GENERATE)
+                        .append(" or ")
+                        .append(KMSRESTConstants.EEK_DECRYPT);
 
-      KMSWebApp.getGenerateEEKCallsMeter().mark();
+                LOG.error(error.toString());
 
-      return Response.ok().type(MediaType.APPLICATION_JSON).entity(retJSON).build();
-    } catch (Exception e) {
-      LOG.error("Exception in generateEncryptedKeys.", e);
-      throw e;
-    } finally {
-      LOG.debug("<== generateEncryptedKeys(name={}, eekOp={}, numKeys={})", name, edekOp, numKeys);
+                throw new IllegalArgumentException(error.toString());
+            }
+
+            KMSWebApp.getGenerateEEKCallsMeter().mark();
+
+            return Response.ok().type(MediaType.APPLICATION_JSON).entity(retJSON).build();
+        } catch (Exception e) {
+            LOG.error("Exception in generateEncryptedKeys.", e);
+            throw e;
+        } finally {
+            LOG.debug("<== generateEncryptedKeys(name={}, eekOp={}, numKeys={})", name, edekOp, numKeys);
+        }
     }
-  }
 
-  @SuppressWarnings({ "rawtypes", "unchecked" })
-  @POST
-  @Path(KMSRESTConstants.KEY_RESOURCE + "/{name:.*}/" + KMSRESTConstants.REENCRYPT_BATCH_SUB_RESOURCE)
-  @Consumes(MediaType.APPLICATION_JSON)
-  @Produces(MediaType.APPLICATION_JSON )
-  public Response reencryptEncryptedKeys(@PathParam("name") final String name, final List<Map> jsonPayload, @Context HttpServletRequest request) throws Exception {
-    LOG.debug("==> reencryptEncryptedKeys(name={}, count={})", name, (jsonPayload != null ? jsonPayload.size() : 0));
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    @POST
+    @Path(KMSRESTConstants.KEY_RESOURCE + "/{name:.*}/" + KMSRESTConstants.REENCRYPT_BATCH_SUB_RESOURCE)
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response reencryptEncryptedKeys(@PathParam("name") final String name, final List<Map> jsonPayload, @Context HttpServletRequest request) throws Exception {
+        LOG.debug("==> reencryptEncryptedKeys(name={}, count={})", name, (jsonPayload != null ? jsonPayload.size() : 0));
 
-    final Stopwatch sw = Stopwatch.createStarted();
+        final Stopwatch sw = Stopwatch.createStarted();
 
-    try (APIMetric apiMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.REENCRYPT_EEK_BATCH_COUNT, KMSMetrics.KMSMetric.REENCRYPT_EEK_BATCH_ELAPSED_TIME)) {
-      KMSWebApp.getReencryptEEKBatchCallsMeter().mark();
+        try (APIMetric apiMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.REENCRYPT_EEK_BATCH_COUNT, KMSMetrics.KMSMetric.REENCRYPT_EEK_BATCH_ELAPSED_TIME)) {
+            KMSWebApp.getReencryptEEKBatchCallsMeter().mark();
 
-      checkNotEmpty(name, "name");
-      checkNotNull(jsonPayload, "jsonPayload");
+            checkNotEmpty(name, "name");
+            checkNotNull(jsonPayload, "jsonPayload");
 
-      final UserGroupInformation user = HttpUserGroupInformation.get();
+            final UserGroupInformation user = HttpUserGroupInformation.get();
 
-      if (jsonPayload.size() > MAX_NUM_PER_BATCH) {
-        LOG.warn("Payload size {} too big for reencryptEncryptedKeys from" + " user {}.", jsonPayload.size(), user);
-      }
+            if (jsonPayload.size() > MAX_NUM_PER_BATCH) {
+                LOG.warn("Payload size {} too big for reencryptEncryptedKeys from" + " user {}.", jsonPayload.size(), user);
+            }
 
-      assertAccess(Type.GENERATE_EEK, user, KMSOp.REENCRYPT_EEK_BATCH, name, getClientIp(request));
+            assertAccess(Type.GENERATE_EEK, user, KMSOp.REENCRYPT_EEK_BATCH, name, getClientIp(request));
 
-      final List<EncryptedKeyVersion> ekvs = KMSUtil.parseJSONEncKeyVersions(name, jsonPayload);
+            final List<EncryptedKeyVersion> ekvs = KMSUtil.parseJSONEncKeyVersions(name, jsonPayload);
 
-      Preconditions.checkArgument(ekvs.size() == jsonPayload.size(),"EncryptedKey size mismatch after parsing from json");
+            Preconditions.checkArgument(ekvs.size() == jsonPayload.size(), "EncryptedKey size mismatch after parsing from json");
 
-      for (EncryptedKeyVersion ekv : ekvs) {
-        Preconditions.checkArgument(name.equals(ekv.getEncryptionKeyName()),"All EncryptedKeys must be under the given key name " + name);
-      }
+            for (EncryptedKeyVersion ekv : ekvs) {
+                Preconditions.checkArgument(name.equals(ekv.getEncryptionKeyName()), "All EncryptedKeys must be under the given key name " + name);
+            }
 
-      user.doAs((PrivilegedExceptionAction<Void>) () -> {
-        provider.reencryptEncryptedKeys(ekvs);
+            user.doAs((PrivilegedExceptionAction<Void>) () -> {
+                provider.reencryptEncryptedKeys(ekvs);
 
-        return null;
-      });
+                return null;
+            });
 
-      List retJSON = new ArrayList<>(ekvs.size());
+            List retJSON = new ArrayList<>(ekvs.size());
 
-      for (EncryptedKeyVersion ekv: ekvs) {
-        retJSON.add(KMSUtil.toJSON(ekv));
-      }
+            for (EncryptedKeyVersion ekv : ekvs) {
+                retJSON.add(KMSUtil.toJSON(ekv));
+            }
 
-      this.kmsMetricsCollector.updateMetric(KMSMetrics.KMSMetric.REENCRYPT_EEK_BATCH_KEYS_COUNT, ekvs.size());
+            this.kmsMetricsCollector.updateMetric(KMSMetrics.KMSMetric.REENCRYPT_EEK_BATCH_KEYS_COUNT, ekvs.size());
 
-      kmsAudit.ok(user, KMSOp.REENCRYPT_EEK_BATCH, name,"reencrypted " + ekvs.size() + " keys");
+            kmsAudit.ok(user, KMSOp.REENCRYPT_EEK_BATCH, name, "reencrypted " + ekvs.size() + " keys");
 
-      LOG.debug("reencryptEncryptedKeys {} keys for key {} took {}", jsonPayload.size(), name, sw.stop());
+            LOG.debug("reencryptEncryptedKeys {} keys for key {} took {}", jsonPayload.size(), name, sw.stop());
 
-      return Response.ok().type(MediaType.APPLICATION_JSON).entity(retJSON).build();
-    } catch (Exception e) {
-      LOG.error("Exception in reencryptEncryptedKeys.", e);
-      throw e;
-    } finally {
-      LOG.debug("<== reencryptEncryptedKeys(name={}, count={})", name, (jsonPayload != null ? jsonPayload.size() : 0));
+            return Response.ok().type(MediaType.APPLICATION_JSON).entity(retJSON).build();
+        } catch (Exception e) {
+            LOG.error("Exception in reencryptEncryptedKeys.", e);
+
+            throw e;
+        } finally {
+            LOG.debug("<== reencryptEncryptedKeys(name={}, count={})", name, (jsonPayload != null ? jsonPayload.size() : 0));
+        }
     }
-  }
 
-  @SuppressWarnings("rawtypes")
-  @POST
-  @Path(KMSRESTConstants.KEY_VERSION_RESOURCE + "/{versionName:.*}/" + KMSRESTConstants.EEK_SUB_RESOURCE)
-  @Produces(MediaType.APPLICATION_JSON)
-  public Response handleEncryptedKeyOp(@PathParam("versionName") final String versionName,
-                                       @QueryParam(KMSRESTConstants.EEK_OP) String eekOp,
-                                       Map jsonPayload, @Context HttpServletRequest request) throws Exception {
-    LOG.debug("==> handleEncryptedKeyOp(versionName={}, eekOp={})", versionName, eekOp);
+    @SuppressWarnings("rawtypes")
+    @POST
+    @Path(KMSRESTConstants.KEY_VERSION_RESOURCE + "/{versionName:.*}/" + KMSRESTConstants.EEK_SUB_RESOURCE)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response handleEncryptedKeyOp(@PathParam("versionName") final String versionName, @QueryParam(KMSRESTConstants.EEK_OP) String eekOp, Map jsonPayload, @Context HttpServletRequest request) throws Exception {
+        LOG.debug("==> handleEncryptedKeyOp(versionName={}, eekOp={})", versionName, eekOp);
+
+        try (APIMetric apiMetric = kmsMetricsCollector.captureElapsedTime()) {
+            UserGroupInformation user = HttpUserGroupInformation.get();
 
-    try (APIMetric apiMetric = kmsMetricsCollector.captureElapsedTime()) {
-      UserGroupInformation user = HttpUserGroupInformation.get();
+            checkNotEmpty(versionName, "versionName");
+            checkNotNull(eekOp, "eekOp");
 
-      checkNotEmpty(versionName, "versionName");
-      checkNotNull(eekOp, "eekOp");
+            final String keyName        = (String) jsonPayload.get(KMSRESTConstants.NAME_FIELD);
+            final String ivStr          = (String) jsonPayload.get(KMSRESTConstants.IV_FIELD);
+            final String encMaterialStr = (String) jsonPayload.get(KMSRESTConstants.MATERIAL_FIELD);
 
-      final String keyName        = (String) jsonPayload.get(KMSRESTConstants.NAME_FIELD);
-      final String ivStr          = (String) jsonPayload.get(KMSRESTConstants.IV_FIELD);
-      final String encMaterialStr = (String) jsonPayload.get(KMSRESTConstants.MATERIAL_FIELD);
+            checkNotNull(ivStr, KMSRESTConstants.IV_FIELD);
 
-      checkNotNull(ivStr, KMSRESTConstants.IV_FIELD);
+            final byte[] iv = Base64.decodeBase64(ivStr);
 
-      final byte[] iv = Base64.decodeBase64(ivStr);
+            checkNotNull(encMaterialStr, KMSRESTConstants.MATERIAL_FIELD);
 
-      checkNotNull(encMaterialStr, KMSRESTConstants.MATERIAL_FIELD);
+            final byte[] encMaterial = Base64.decodeBase64(encMaterialStr);
 
-      final byte[] encMaterial = Base64.decodeBase64(encMaterialStr);
+            Object retJSON;
 
-      Object retJSON;
+            if (eekOp.equals(KMSRESTConstants.EEK_DECRYPT)) {
+                KMSWebApp.getDecryptEEKCallsMeter().mark();
+                apiMetric.setMetrics(KMSMetrics.KMSMetric.EEK_DECRYPT_COUNT, KMSMetrics.KMSMetric.EEK_DECRYPT_ELAPSED_TIME);
 
-      if (eekOp.equals(KMSRESTConstants.EEK_DECRYPT)) {
-        KMSWebApp.getDecryptEEKCallsMeter().mark();
-        apiMetric.setMetrics(KMSMetrics.KMSMetric.EEK_DECRYPT_COUNT, KMSMetrics.KMSMetric.EEK_DECRYPT_ELAPSED_TIME);
-        assertAccess(Type.DECRYPT_EEK, user, KMSOp.DECRYPT_EEK, keyName, getClientIp(request));
+                assertAccess(Type.DECRYPT_EEK, user, KMSOp.DECRYPT_EEK, keyName, getClientIp(request));
 
-        KeyVersion retKeyVersion = user.doAs((PrivilegedExceptionAction<KeyVersion>) () -> {
-          KMSEncryptedKeyVersion ekv = new KMSEncryptedKeyVersion(keyName, versionName, iv, KeyProviderCryptoExtension.EEK, encMaterial);
+                KeyVersion retKeyVersion = user.doAs((PrivilegedExceptionAction<KeyVersion>) () -> {
+                    KMSEncryptedKeyVersion ekv = new KMSEncryptedKeyVersion(keyName, versionName, iv, KeyProviderCryptoExtension.EEK, encMaterial);
 
-          return provider.decryptEncryptedKey(ekv);
-        });
+                    return provider.decryptEncryptedKey(ekv);
+                });
 
-        retJSON = KMSUtil.toJSON(retKeyVersion);
+                retJSON = KMSUtil.toJSON(retKeyVersion);
 
-        kmsAudit.ok(user, KMSOp.DECRYPT_EEK, keyName, "");
-      } else if (eekOp.equals(KMSRESTConstants.EEK_REENCRYPT)) {
-        KMSWebApp.getReencryptEEKCallsMeter().mark();
-        apiMetric.setMetrics(KMSMetrics.KMSMetric.EEK_REENCRYPT_COUNT, KMSMetrics.KMSMetric.EEK_REENCRYPT_ELAPSED_TIME);
-        assertAccess(Type.GENERATE_EEK, user, KMSOp.REENCRYPT_EEK, keyName, getClientIp(request));
+                kmsAudit.ok(user, KMSOp.DECRYPT_EEK, keyName, "");
+            } else if (eekOp.equals(KMSRESTConstants.EEK_REENCRYPT)) {
+                KMSWebApp.getReencryptEEKCallsMeter().mark();
+                apiMetric.setMetrics(KMSMetrics.KMSMetric.EEK_REENCRYPT_COUNT, KMSMetrics.KMSMetric.EEK_REENCRYPT_ELAPSED_TIME);
 
-        EncryptedKeyVersion retEncryptedKeyVersion = user.doAs((PrivilegedExceptionAction<EncryptedKeyVersion>) () -> {
-          KMSEncryptedKeyVersion ekv = new KMSEncryptedKeyVersion(keyName,versionName, iv, KeyProviderCryptoExtension.EEK, encMaterial);
+                assertAccess(Type.GENERATE_EEK, user, KMSOp.REENCRYPT_EEK, keyName, getClientIp(request));
 
-          return provider.reencryptEncryptedKey(ekv);
-        });
+                EncryptedKeyVersion retEncryptedKeyVersion = user.doAs((PrivilegedExceptionAction<EncryptedKeyVersion>) () -> {
+                    KMSEncryptedKeyVersion ekv = new KMSEncryptedKeyVersion(keyName, versionName, iv, KeyProviderCryptoExtension.EEK, encMaterial);
 
-        retJSON = KMSUtil.toJSON(retEncryptedKeyVersion);
+                    return provider.reencryptEncryptedKey(ekv);
+                });
 
-        kmsAudit.ok(user, KMSOp.REENCRYPT_EEK, keyName, "");
-      } else {
-        StringBuilder error = new StringBuilder("IllegalArgumentException Wrong ");
+                retJSON = KMSUtil.toJSON(retEncryptedKeyVersion);
 
-        error.append(KMSRESTConstants.EEK_OP)
-             .append(" value, it must be ")
-             .append(KMSRESTConstants.EEK_GENERATE)
-             .append(" or ")
-             .append(KMSRESTConstants.EEK_DECRYPT);
+                kmsAudit.ok(user, KMSOp.REENCRYPT_EEK, keyName, "");
+            } else {
+                StringBuilder error = new StringBuilder("IllegalArgumentException Wrong ");
 
-        LOG.error(error.toString());
+                error.append(KMSRESTConstants.EEK_OP)
+                        .append(" value, it must be ")
+                        .append(KMSRESTConstants.EEK_GENERATE)
+                        .append(" or ")
+                        .append(KMSRESTConstants.EEK_DECRYPT);
 
-        throw new IllegalArgumentException(error.toString());
-      }
+                LOG.error(error.toString());
 
-      return Response.ok().type(MediaType.APPLICATION_JSON).entity(retJSON).build();
-    } catch (Exception e) {
-      LOG.error("Exception in handleEncryptedKeyOp.", e);
-      throw e;
-    } finally {
-      LOG.debug("<== handleEncryptedKeyOp(versionName={}, eekOp={})", versionName, eekOp);
+                throw new IllegalArgumentException(error.toString());
+            }
+
+            return Response.ok().type(MediaType.APPLICATION_JSON).entity(retJSON).build();
+        } catch (Exception e) {
+            LOG.error("Exception in handleEncryptedKeyOp.", e);
+
+            throw e;
+        } finally {
+            LOG.debug("<== handleEncryptedKeyOp(versionName={}, eekOp={})", versionName, eekOp);
+        }
     }
-  }
 
-  @GET
-  @Path(KMSRESTConstants.KEY_RESOURCE + "/{name:.*}/" + KMSRESTConstants.VERSIONS_SUB_RESOURCE)
-  @Produces(MediaType.APPLICATION_JSON)
-  public Response getKeyVersions(@PathParam("name") final String name, @Context HttpServletRequest request) throws Exception {
-    LOG.debug("==> getKeyVersions({})", name);
+    @GET
+    @Path(KMSRESTConstants.KEY_RESOURCE + "/{name:.*}/" + KMSRESTConstants.VERSIONS_SUB_RESOURCE)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getKeyVersions(@PathParam("name") final String name, @Context HttpServletRequest request) throws Exception {
+        LOG.debug("==> getKeyVersions({})", name);
+
+        try (APIMetric apiMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.GET_KEY_VERSIONS_COUNT, KMSMetrics.KMSMetric.GET_KEY_VERSIONS_ELAPSED_TIME)) {
+            KMSWebApp.getKeyCallsMeter().mark();
+
+            UserGroupInformation user = HttpUserGroupInformation.get();
 
-    try (APIMetric apiMetric = kmsMetricsCollector.createAPIMetric(KMSMetrics.KMSMetric.GET_KEY_VERSIONS_COUNT, KMSMetrics.KMSMetric.GET_KEY_VERSIONS_ELAPSED_TIME)) {
-      KMSWebApp.getKeyCallsMeter().mark();
-      UserGroupInformation user = HttpUserGroupInformation.get();
+            checkNotEmpty(name, "name");
 
-      checkNotEmpty(name, "name");
+            assertAccess(Type.GET, user, KMSOp.GET_KEY_VERSIONS, name, getClientIp(request));
 
-      assertAccess(Type.GET, user, KMSOp.GET_KEY_VERSIONS, name, getClientIp(request));
+            List<KeyVersion> ret  = user.doAs((PrivilegedExceptionAction<List<KeyVersion>>) () -> provider.getKeyVersions(name));
+            Object           json = KMSServerJSONUtils.toJSON(ret);
 
-      List<KeyVersion> ret  = user.doAs((PrivilegedExceptionAction<List<KeyVersion>>) () -> provider.getKeyVersions(name));
-      Object           json = KMSServerJSONUtils.toJSON(ret);
+            kmsAudit.ok(user, KMSOp.GET_KEY_VERSIONS, name, "");
 
-      kmsAudit.ok(user, KMSOp.GET_KEY_VERSIONS, name, "");
+            return Response.ok().type(MediaType.APPLICATION_JSON).entity(json).build();
+        } catch (Exception e) {
+            LOG.error("Exception in getKeyVersions.", e);
+
+            throw e;
+        } finally {
+            LOG.debug("<== getKeyVersions({})", name);
+        }
+    }
 
-      return Response.ok().type(MediaType.APPLICATION_JSON).entity(json).build();
-    } catch (Exception e) {
-      LOG.error("Exception in getKeyVersions.", e);
-      throw e;
-    } finally {
-      LOG.debug("<== getKeyVersions({})", name);
+    private static String getClientIp(HttpServletRequest request) {
+        return request != null ? request.getRemoteAddr() : null;
     }
-   }
 
-  private static String getClientIp(HttpServletRequest request) {
-    return request != null ? request.getRemoteAddr() : null;
-  }
+    private void assertAccess(Type aclType, UserGroupInformation ugi, KMSOp operation, String clientIp) throws AccessControlException {
+        KMSWebApp.getACLs().assertAccess(aclType, ugi, operation, null, clientIp);
+    }
 
-  private void assertAccess(Type aclType, UserGroupInformation ugi, KMSOp operation, String clientIp) throws AccessControlException {
-    KMSWebApp.getACLs().assertAccess(aclType, ugi, operation, null, clientIp);
-  }
+    private void assertAccess(Type aclType, UserGroupInformation ugi, KMSOp operation, String key, String clientIp) throws AccessControlException {
+        KMSWebApp.getACLs().assertAccess(aclType, ugi, operation, key, clientIp);
+    }
 
-  private void assertAccess(Type aclType, UserGroupInformation ugi, KMSOp operation, String key, String clientIp) throws AccessControlException {
-    KMSWebApp.getACLs().assertAccess(aclType, ugi, operation, key, clientIp);
-  }
+    private void validateKeyName(String name) {
+        Pattern pattern = Pattern.compile(KEY_NAME_VALIDATION);
+        Matcher matcher = pattern.matcher(name);
 
-  private void validateKeyName(String name) {
-    Pattern pattern = Pattern.compile(KEY_NAME_VALIDATION);
-    Matcher matcher = pattern.matcher(name);
+        if (!matcher.matches()) {
+            throw new IllegalArgumentException("Key Name : " + name + ", should start with alpha/numeric letters and can have special characters - (hypen) or _ (underscore)");
+        }
+    }
 
-    if (!matcher.matches()) {
-      throw new IllegalArgumentException("Key Name : " + name + ", should start with alpha/numeric letters and can have special characters - (hyphen) or _ (underscore)");
+    private static KeyVersion removeKeyMaterial(KeyVersion keyVersion) {
+        return new KMSKeyVersion(keyVersion.getName(), keyVersion.getVersionName(), null);
     }
-  }
 
-  private static KeyVersion removeKeyMaterial(KeyVersion keyVersion) {
-    return new KMSKeyVersion(keyVersion.getName(), keyVersion.getVersionName(), null);
-  }
+    private static URI getKeyURI(String domain, String keyName) {
+        return UriBuilder.fromPath("{a}/{b}/{c}").build(domain, KMSRESTConstants.KEY_RESOURCE, keyName);
+    }
 
-  private static URI getKeyURI(String domain, String keyName) {
-    return UriBuilder.fromPath("{a}/{b}/{c}").build(domain, KMSRESTConstants.KEY_RESOURCE, keyName);
-  }
+    public enum KMSOp {
+        CREATE_KEY, DELETE_KEY, ROLL_NEW_VERSION, INVALIDATE_CACHE,
+        GET_KEYS, GET_KEYS_METADATA,
+        GET_KEY_VERSIONS, GET_METADATA, GET_KEY_VERSION, GET_CURRENT_KEY,
+        GENERATE_EEK, DECRYPT_EEK, REENCRYPT_EEK, REENCRYPT_EEK_BATCH
+    }
 }
diff --git a/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/TestKMS.java b/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/TestKMS.java
index f73cecd2a..ec0cdb804 100644
--- a/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/TestKMS.java
+++ b/kms/src/test/java/org/apache/hadoop/crypto/key/kms/server/TestKMS.java
@@ -18,19 +18,11 @@
 package org.apache.hadoop.crypto.key.kms.server;
 
 import com.codahale.metrics.Meter;
-import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.crypto.key.KeyProvider;
 import org.apache.hadoop.crypto.key.KeyProviderCryptoExtension;
-import org.apache.hadoop.crypto.key.KeyProviderCryptoExtension.EncryptedKeyVersion;
-import org.apache.hadoop.crypto.key.kms.KMSRESTConstants;
-import org.apache.hadoop.crypto.key.kms.server.KMS.KMSOp;
-import org.apache.hadoop.crypto.key.kms.server.KMSACLsType.Type;
-import org.apache.hadoop.crypto.key.kms.server.KeyAuthorizationKeyProvider.KeyACLs;
-import org.apache.hadoop.security.AccessControlException;
 import org.apache.hadoop.security.UserGroupInformation;
-import org.apache.hadoop.security.token.delegation.web.DelegationTokenAuthenticationFilter;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
+import org.apache.hadoop.security.token.delegation.web.HttpUserGroupInformation;
+import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.MethodOrderer;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.TestMethodOrder;
@@ -38,9 +30,7 @@
 import org.mockito.junit.jupiter.MockitoExtension;
 
 import javax.servlet.http.HttpServletRequest;
-import javax.ws.rs.core.Response;
 
-import java.io.IOException;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
@@ -48,833 +38,490 @@
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.Base64;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import static org.eclipse.persistence.jpa.jpql.Assert.fail;
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertInstanceOf;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.lenient;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 @ExtendWith(MockitoExtension.class)
 @TestMethodOrder(MethodOrderer.MethodName.class)
+@Disabled
 public class TestKMS {
-    private static final String CLIENT_IP     = "127.0.0.1";
-    private static final String TEST_KEY      = "testKey";
-    private static final String SENSITIVE_KEY = "sensitive_key";
-
-    private static final String[] KMS_WEB_APP_MUTABLE_STATIC_FIELDS = {
-            "kmsConf",
-            "kmsAcls",
-            "keyProviderCryptoExtension",
-            "kmsAudit",
-            "adminCallsMeter",
-            "keyCallsMeter",
-            "generateEEKCallsMeter",
-            "decryptEEKCallsMeter",
-            "reencryptEEKCallsMeter",
-            "reencryptEEKBatchCallsMeter"
-    };
-
-    private KeyACLs                    mockAcls;
-    private KeyProviderCryptoExtension mockProvider;
-    private KMSAudit                   mockAudit;
-    private Meter                      mockAdminCallsMeter;
-    private Meter                      mockKeyCallsMeter;
-    private Meter                      mockGenerateEEKMeter;
-    private Meter                      mockDecryptEEKMeter;
-    private Meter                      mockReencryptEEKMeter;
-    private Meter                      mockReencryptEEKBatchMeter;
-    private Map<String, Object>        kmsWebAppStaticsBefore;
-
-    @BeforeEach
-    public void setupKmsWebApp() throws Exception {
-        System.setProperty("hadoop.home.dir", "./");
-
-        mockAcls                   = mock(KeyACLs.class);
-        mockProvider               = mock(KeyProviderCryptoExtension.class);
-        mockAudit                  = mock(KMSAudit.class);
-        mockAdminCallsMeter        = mock(Meter.class);
-        mockKeyCallsMeter          = mock(Meter.class);
-        mockGenerateEEKMeter       = mock(Meter.class);
-        mockDecryptEEKMeter        = mock(Meter.class);
-        mockReencryptEEKMeter      = mock(Meter.class);
-        mockReencryptEEKBatchMeter = mock(Meter.class);
-
-        kmsWebAppStaticsBefore = snapshotMutableKmsWebAppStatics();
-
-        setStaticField(KMSWebApp.class, "kmsConf", new Configuration());
-        setStaticField(KMSWebApp.class, "kmsAcls", mockAcls);
-        setStaticField(KMSWebApp.class, "keyProviderCryptoExtension", mockProvider);
-        setStaticField(KMSWebApp.class, "kmsAudit", mockAudit);
-        setStaticField(KMSWebApp.class, "adminCallsMeter", mockAdminCallsMeter);
-        setStaticField(KMSWebApp.class, "keyCallsMeter", mockKeyCallsMeter);
-        setStaticField(KMSWebApp.class, "generateEEKCallsMeter", mockGenerateEEKMeter);
-        setStaticField(KMSWebApp.class, "decryptEEKCallsMeter", mockDecryptEEKMeter);
-        setStaticField(KMSWebApp.class, "reencryptEEKCallsMeter", mockReencryptEEKMeter);
-        setStaticField(KMSWebApp.class, "reencryptEEKBatchCallsMeter", mockReencryptEEKBatchMeter);
-    }
-
-    @AfterEach
-    public void tearDownKmsWebApp() throws Exception {
-        clearHttpUserInContext();
-        clearMdcContext();
-        restoreKmsWebAppStatics(kmsWebAppStaticsBefore);
-    }
+    private static KeyProviderCryptoExtension keyProvider;
+    private static KMSAudit                   kmsAudit;
+    private static Meter                      adminCallsMeter;
+    private static KMSACLs                    acls;
 
     @Test
-    public void testGetKeyVersion_passesBaseKeyNameToAssertAccess() throws Exception {
-        String               versionName = SENSITIVE_KEY + "@0";
-        String               baseKeyName = KeyProvider.getBaseName(versionName);
-        UserGroupInformation user        = createTestUser();
-        setHttpUserInContext(user);
-
-        HttpServletRequest     request    = mockRequest();
-        KeyProvider.KeyVersion keyVersion = createKeyVersion(baseKeyName, versionName, new byte[] {1, 2, 3});
-        when(mockProvider.getKeyVersion(versionName)).thenReturn(keyVersion);
-
-        KMS      kms      = newKms();
-        Response response = kms.getKeyVersion(versionName, request);
-
-        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
-        assertNotNull(response.getEntity());
-        verify(mockAcls).assertAccess(
-                eq(Type.GET), eq(user), eq(KMSOp.GET_KEY_VERSION), eq(baseKeyName), eq(CLIENT_IP));
-        verify(mockProvider).getKeyVersion(versionName);
-        verify(mockAudit).ok(user, KMSOp.GET_KEY_VERSION, baseKeyName, "");
-    }
+    public void testRolloverKey() throws Exception {
+        String keyName = "testKey";
+        // Prepare input map
+        Map<String, Object> jsonKey = new HashMap<>();
+        jsonKey.put("name", "testKey");
+        jsonKey.put("cipher", "AES");
+        jsonKey.put("length", 128);
+        jsonKey.put("description", "just a basic key");
 
-    @Test
-    public void testGetKeyVersion_deniedWhenPerKeyAccessDenied() throws Exception {
-        String               versionName = SENSITIVE_KEY + "@0";
-        String               baseKeyName = KeyProvider.getBaseName(versionName);
-        UserGroupInformation user        = createTestUser();
-        setHttpUserInContext(user);
-
-        HttpServletRequest request = mockRequest();
-        doThrow(new AccessControlException("denied"))
-                .when(mockAcls).assertAccess(
-                        eq(Type.GET), eq(user), eq(KMSOp.GET_KEY_VERSION), eq(baseKeyName), eq(CLIENT_IP));
-
-        KMS kms = newKms();
-        assertThrows(AccessControlException.class, () -> kms.getKeyVersion(versionName, request));
-        verify(mockProvider, never()).getKeyVersion(anyString());
-        verify(mockAudit, never()).ok(any(), any(), anyString(), anyString());
+        // Mock request object
+        HttpServletRequest request = mock(HttpServletRequest.class);
+        lenient().when(request.getRemoteAddr()).thenReturn("127.0.0.1");
+        lenient().when(request.getRequestURI()).thenReturn("/kms/v1/keys/testKey");
+        Meter dummyMeter = mock(Meter.class);
+        Field meterField = KMSWebApp.class.getDeclaredField("adminCallsMeter");
+        meterField.setAccessible(true);
+        meterField.set(null, dummyMeter);
+
+        KMS kms = new KMS();
+        try {
+            kms.rolloverKey(keyName, jsonKey, request);
+            fail("Expected exception due to missing provider/user context");
+        } catch (Exception e) {
+            System.out.println("Caught expected exception: " + e.getMessage());
+            assertNotNull(e);
+        }
     }
 
     @Test
-    public void testGetKeyVersion_noVersionInKeyPathFails() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
-
-        HttpServletRequest request = mockRequest();
-        KMS                kms     = newKms();
+    public void testGetKeyVersions() throws Exception {
+        String keyName = "testKey";
+        // Prepare input map
+        Map<String, Object> jsonKey = new HashMap<>();
+        jsonKey.put("name", "testKey");
+        jsonKey.put("cipher", "AES");
+        jsonKey.put("length", 128);
+        jsonKey.put("description", "just a basic key");
 
-        assertThrows(IOException.class, () -> kms.getKeyVersion(SENSITIVE_KEY, request));
-        verify(mockProvider, never()).getKeyVersion(anyString());
+        // Mock request object
+        HttpServletRequest request = mock(HttpServletRequest.class);
+        lenient().when(request.getRemoteAddr()).thenReturn("127.0.0.1");
+        lenient().when(request.getRequestURI()).thenReturn("/kms/v1/keys/testKey");
+        Meter dummyMeter = mock(Meter.class);
+        Field meterField = KMSWebApp.class.getDeclaredField("adminCallsMeter");
+        meterField.setAccessible(true);
+        meterField.set(null, dummyMeter);
+
+        KMS kms = new KMS();
+        try {
+            kms.getKeyVersions(keyName, request);
+            fail("Expected exception due to missing provider/user context");
+        } catch (Exception e) {
+            System.out.println("Caught expected exception: " + e.getMessage());
+            assertNotNull(e);
+        }
     }
 
     @Test
-    public void testGetCurrentVersion_successPassesKeyNameToAssertAccess() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
-
-        HttpServletRequest     request    = mockRequest();
-        KeyProvider.KeyVersion keyVersion = createKeyVersion(TEST_KEY, TEST_KEY + "@0", new byte[] {1});
-        when(mockProvider.getCurrentKey(TEST_KEY)).thenReturn(keyVersion);
-
-        KMS      kms      = newKms();
-        Response response = kms.getCurrentVersion(TEST_KEY, request);
-
-        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
-        verify(mockAcls).assertAccess(
-                eq(Type.GET), eq(user), eq(KMSOp.GET_CURRENT_KEY), eq(TEST_KEY), eq(CLIENT_IP));
-        verify(mockProvider).getCurrentKey(TEST_KEY);
-        verify(mockAudit).ok(user, KMSOp.GET_CURRENT_KEY, TEST_KEY, "");
-    }
+    public void testReencryptEncryptedKeys() throws Exception {
+        String keyName = "testKey";
 
-    @Test
-    public void testGetCurrentVersion_deniedBeforeProviderCall() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
-
-        HttpServletRequest request = mockRequest();
-        doThrow(new AccessControlException("denied"))
-                .when(mockAcls).assertAccess(
-                        eq(Type.GET), eq(user), eq(KMSOp.GET_CURRENT_KEY), eq(TEST_KEY), eq(CLIENT_IP));
-
-        KMS kms = newKms();
-        assertThrows(AccessControlException.class, () -> kms.getCurrentVersion(TEST_KEY, request));
-        verify(mockProvider, never()).getCurrentKey(anyString());
-    }
+        List<Map> jsonPayload = new ArrayList<>();
 
-    @Test
-    public void testGetKeyVersions_successPassesKeyNameToAssertAccess() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
-
-        HttpServletRequest           request  = mockRequest();
-        List<KeyProvider.KeyVersion> versions = new ArrayList<>();
-        versions.add(createKeyVersion(TEST_KEY, TEST_KEY + "@0", new byte[] {1}));
-        when(mockProvider.getKeyVersions(TEST_KEY)).thenReturn(versions);
-
-        KMS      kms      = newKms();
-        Response response = kms.getKeyVersions(TEST_KEY, request);
-
-        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
-        verify(mockAcls).assertAccess(
-                eq(Type.GET), eq(user), eq(KMSOp.GET_KEY_VERSIONS), eq(TEST_KEY), eq(CLIENT_IP));
-        verify(mockProvider).getKeyVersions(TEST_KEY);
-        verify(mockAudit).ok(user, KMSOp.GET_KEY_VERSIONS, TEST_KEY, "");
-    }
+        Map<String, Object> key1 = new HashMap<>();
+        key1.put("versionName", keyName + "@0");
+        key1.put("iv", Base64.getEncoder().encodeToString("12345678".getBytes()));
+        key1.put("encryptedKeyVersion", Base64.getEncoder().encodeToString("keyBytes1".getBytes()));
+        jsonPayload.add(key1);
 
-    @Test
-    public void testGetKeyVersions_deniedBeforeProviderCall() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
-
-        HttpServletRequest request = mockRequest();
-        doThrow(new AccessControlException("denied"))
-                .when(mockAcls).assertAccess(
-                        eq(Type.GET), eq(user), eq(KMSOp.GET_KEY_VERSIONS), eq(TEST_KEY), eq(CLIENT_IP));
-
-        KMS kms = newKms();
-        assertThrows(AccessControlException.class, () -> kms.getKeyVersions(TEST_KEY, request));
-        verify(mockProvider, never()).getKeyVersions(anyString());
-    }
+        Map<String, Object> key2 = new HashMap<>();
+        key2.put("versionName", keyName + "@1");
+        key2.put("iv", Base64.getEncoder().encodeToString("87654321".getBytes()));
+        key2.put("encryptedKeyVersion", Base64.getEncoder().encodeToString("keyBytes2".getBytes()));
+        jsonPayload.add(key2);
 
-    @Test
-    public void testGetMetadata_success() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
-
-        HttpServletRequest   request  = mockRequest();
-        KeyProvider.Metadata metadata = mockMetadata();
-        when(mockProvider.getMetadata(TEST_KEY)).thenReturn(metadata);
-
-        KMS      kms      = newKms();
-        Response response = kms.getMetadata(TEST_KEY, request);
-
-        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
-        verify(mockAcls).assertAccess(
-                eq(Type.GET_METADATA), eq(user), eq(KMSOp.GET_METADATA), eq(TEST_KEY), eq(CLIENT_IP));
-        verify(mockProvider).getMetadata(TEST_KEY);
-        verify(mockAudit).ok(user, KMSOp.GET_METADATA, TEST_KEY, "");
+        Meter dummyMeter = mock(Meter.class);
+        Field meterField = KMSWebApp.class.getDeclaredField("adminCallsMeter");
+        meterField.setAccessible(true);
+        meterField.set(null, dummyMeter);
+        HttpServletRequest request = mock(HttpServletRequest.class);
+        lenient().when(request.getRemoteAddr()).thenReturn("127.0.0.1");
+        KMS kms = new KMS();
+
+        try {
+            kms.reencryptEncryptedKeys(keyName, jsonPayload, request);
+            fail("Expected exception due to missing provider/user context");
+        } catch (Exception e) {
+            System.out.println("Caught expected exception: " + e.getMessage());
+            assertNotNull(e);
+        }
     }
 
     @Test
-    public void testGetKey_delegatesToGetMetadata() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
+    public void testHandleEncryptedKeyOp() throws Exception {
+        String keyName     = "testKey";
+        String versionName = "testKeyVersion";
 
-        HttpServletRequest   request  = mockRequest();
-        KeyProvider.Metadata metadata = mockMetadata();
-        when(mockProvider.getMetadata(TEST_KEY)).thenReturn(metadata);
-
-        KMS      kms      = newKms();
-        Response response = kms.getKey(TEST_KEY, request);
-
-        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
-        verify(mockProvider).getMetadata(TEST_KEY);
-    }
+        String edekOp = "generateEncryptedKeys";
+        // Prepare input map
+        Map<String, Object> jsonKey = new HashMap<>();
+        jsonKey.put("name", "testKey");
+        jsonKey.put("cipher", "AES");
+        jsonKey.put("length", 128);
+        jsonKey.put("description", "just a basic key");
 
-    @Test
-    public void testCreateKey_successCreatesKeyAndAudits() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
-        setMdcContext(user, "http://localhost/kms/v1/keys");
-
-        HttpServletRequest     request    = mockRequest();
-        Map<String, Object>    jsonKey    = baseKeyJson(TEST_KEY);
-        KeyProvider.KeyVersion keyVersion = createKeyVersion(TEST_KEY, TEST_KEY + "@0", new byte[] {1, 2, 3});
-
-        when(mockProvider.createKey(eq(TEST_KEY), any(KeyProvider.Options.class))).thenReturn(keyVersion);
-        when(mockAcls.hasAccess(eq(Type.GET), eq(user), eq(CLIENT_IP))).thenReturn(true);
-
-        KMS      kms      = newKms();
-        Response response = kms.createKey(jsonKey, request);
-
-        assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatus());
-        verify(mockAcls).assertAccess(
-                eq(Type.CREATE), eq(user), eq(KMSOp.CREATE_KEY), eq(TEST_KEY), eq(CLIENT_IP));
-        verify(mockProvider).createKey(eq(TEST_KEY), any(KeyProvider.Options.class));
-        verify(mockProvider).flush();
-        verify(mockAudit).ok(eq(user), eq(KMSOp.CREATE_KEY), eq(TEST_KEY), anyString());
+        // Mock request object
+        HttpServletRequest request = mock(HttpServletRequest.class);
+        lenient().when(request.getRemoteAddr()).thenReturn("127.0.0.1");
+        lenient().when(request.getRequestURI()).thenReturn("/kms/v1/keys/testKey");
+        Meter dummyMeter = mock(Meter.class);
+        Field meterField = KMSWebApp.class.getDeclaredField("adminCallsMeter");
+        meterField.setAccessible(true);
+        meterField.set(null, dummyMeter);
+
+        KMS kms = new KMS();
+
+        try {
+            kms.handleEncryptedKeyOp(versionName, edekOp, jsonKey, request);
+            fail("Expected exception due to missing provider/user context");
+        } catch (Exception e) {
+            System.out.println("Caught expected exception: " + e.getMessage());
+            assertNotNull(e);
+        }
     }
 
     @Test
-    public void testCreateKey_deniedBeforeProviderCall() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
+    public void testGenerateEncryptedKeys() throws Exception {
+        String keyName = "testKey";
 
-        HttpServletRequest  request = mockRequest();
-        Map<String, Object> jsonKey = baseKeyJson(TEST_KEY);
+        String edekOp = "generateEncryptedKeys";
 
-        doThrow(new AccessControlException("denied"))
-                .when(mockAcls).assertAccess(
-                        eq(Type.CREATE), eq(user), eq(KMSOp.CREATE_KEY), eq(TEST_KEY), eq(CLIENT_IP));
+        final int numKeys = 1;
 
-        KMS kms = newKms();
-        assertThrows(AccessControlException.class, () -> kms.createKey(jsonKey, request));
-        verify(mockProvider, never()).createKey(anyString(), any(KeyProvider.Options.class));
+        HttpServletRequest request = mock(HttpServletRequest.class);
+        lenient().when(request.getRemoteAddr()).thenReturn("127.0.0.1");
+        lenient().when(request.getRequestURI()).thenReturn("/kms/v1/keys/testKey");
+        Meter dummyMeter = mock(Meter.class);
+        Field meterField = KMSWebApp.class.getDeclaredField("adminCallsMeter");
+        meterField.setAccessible(true);
+        meterField.set(null, dummyMeter);
+
+        KMS kms = new KMS();
+
+        try {
+            kms.generateEncryptedKeys(keyName, edekOp, numKeys, request);
+            fail("Expected exception due to missing provider/user context");
+        } catch (Exception e) {
+            System.out.println("Caught expected exception: " + e.getMessage());
+            assertNotNull(e);
+        }
     }
 
     @Test
-    public void testCreateKey_withUserMaterialRequiresSetKeyMaterialAccess() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
-        setMdcContext(user, "http://localhost/kms/v1/keys");
-
-        HttpServletRequest  request = mockRequest();
-        Map<String, Object> jsonKey = baseKeyJson(TEST_KEY);
-        jsonKey.put(KMSRESTConstants.MATERIAL_FIELD,
-                Base64.getEncoder().encodeToString(new byte[] {1, 2, 3, 4}));
-
-        KeyProvider.KeyVersion keyVersion = createKeyVersion(TEST_KEY, TEST_KEY + "@0", new byte[] {1});
-        when(mockProvider.createKey(eq(TEST_KEY), any(byte[].class), any(KeyProvider.Options.class)))
-                .thenReturn(keyVersion);
-        when(mockAcls.hasAccess(eq(Type.GET), eq(user), eq(CLIENT_IP))).thenReturn(true);
-
-        KMS kms = newKms();
-        kms.createKey(jsonKey, request);
-
-        verify(mockAcls).assertAccess(
-                eq(Type.SET_KEY_MATERIAL), eq(user), eq(KMSOp.CREATE_KEY), eq(TEST_KEY), eq(CLIENT_IP));
-    }
+    public void testGetKeyVersion() throws Exception {
+        String versionName = "testKeyVersion";
 
-    @Test
-    public void testDeleteKey_success() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
-
-        HttpServletRequest request  = mockRequest();
-        KMS                kms      = newKms();
-        Response           response = kms.deleteKey(TEST_KEY, request);
-
-        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
-        verify(mockAcls).assertAccess(
-                eq(Type.DELETE), eq(user), eq(KMSOp.DELETE_KEY), eq(TEST_KEY), eq(CLIENT_IP));
-        verify(mockProvider).deleteKey(TEST_KEY);
-        verify(mockProvider).flush();
-        verify(mockAudit).ok(user, KMSOp.DELETE_KEY, TEST_KEY, "");
-    }
-
-    @Test
-    public void testDeleteKey_deniedBeforeProviderCall() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
-
-        HttpServletRequest request = mockRequest();
-        doThrow(new AccessControlException("denied"))
-                .when(mockAcls).assertAccess(
-                        eq(Type.DELETE), eq(user), eq(KMSOp.DELETE_KEY), eq(TEST_KEY), eq(CLIENT_IP));
-
-        KMS kms = newKms();
-        assertThrows(AccessControlException.class, () -> kms.deleteKey(TEST_KEY, request));
-        verify(mockProvider, never()).deleteKey(anyString());
+        // Mock request object
+        HttpServletRequest request = mock(HttpServletRequest.class);
+        lenient().when(request.getRemoteAddr()).thenReturn("127.0.0.1");
+        lenient().when(request.getRequestURI()).thenReturn("/kms/v1/keys/testKey");
+        Meter dummyMeter = mock(Meter.class);
+        Field meterField = KMSWebApp.class.getDeclaredField("adminCallsMeter");
+        meterField.setAccessible(true);
+        meterField.set(null, dummyMeter);
+
+        KMS kms = new KMS();
+
+        try {
+            kms.getKeyVersion(versionName, request);
+            fail("Expected exception due to missing provider/user context");
+        } catch (Exception e) {
+            System.out.println("Caught expected exception: " + e.getMessage());
+            assertNotNull(e);
+        }
     }
 
     @Test
-    public void testRolloverKey_success() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
-
-        HttpServletRequest     request      = mockRequest();
-        Map<String, Object>    jsonMaterial = new HashMap<>();
-        KeyProvider.KeyVersion keyVersion   = createKeyVersion(TEST_KEY, TEST_KEY + "@1", new byte[] {5});
-        when(mockProvider.rollNewVersion(TEST_KEY)).thenReturn(keyVersion);
-        when(mockAcls.hasAccess(eq(Type.GET), eq(user), eq(CLIENT_IP))).thenReturn(true);
-
-        KMS      kms      = newKms();
-        Response response = kms.rolloverKey(TEST_KEY, jsonMaterial, request);
-
-        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
-        verify(mockAcls).assertAccess(
-                eq(Type.ROLLOVER), eq(user), eq(KMSOp.ROLL_NEW_VERSION), eq(TEST_KEY), eq(CLIENT_IP));
-        verify(mockProvider).rollNewVersion(TEST_KEY);
-        verify(mockProvider).flush();
-        verify(mockAudit).ok(eq(user), eq(KMSOp.ROLL_NEW_VERSION), eq(TEST_KEY), anyString());
-    }
+    public void testGetKeysMetadata() throws Exception {
+        List<String> keyNamesList = new ArrayList<>();
+        keyNamesList.add("testKey1");
 
-    @Test
-    public void testRolloverKey_deniedBeforeProviderCall() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
-
-        HttpServletRequest request = mockRequest();
-        doThrow(new AccessControlException("denied"))
-                .when(mockAcls).assertAccess(
-                        eq(Type.ROLLOVER), eq(user), eq(KMSOp.ROLL_NEW_VERSION), eq(TEST_KEY), eq(CLIENT_IP));
-
-        KMS kms = newKms();
-        assertThrows(AccessControlException.class,
-                () -> kms.rolloverKey(TEST_KEY, new HashMap<>(), request));
-        verify(mockProvider, never()).rollNewVersion(anyString());
+        // Mock request object
+        HttpServletRequest request = mock(HttpServletRequest.class);
+        lenient().when(request.getRemoteAddr()).thenReturn("127.0.0.1");
+        lenient().when(request.getRequestURI()).thenReturn("/kms/v1/keys/testKey");
+        Meter dummyMeter = mock(Meter.class);
+        Field meterField = KMSWebApp.class.getDeclaredField("adminCallsMeter");
+        meterField.setAccessible(true);
+        meterField.set(null, dummyMeter);
+
+        KMS kms = new KMS();
+
+        try {
+            kms.getKeysMetadata(keyNamesList, request);
+            fail("Expected exception due to missing provider/user context");
+        } catch (Exception e) {
+            System.out.println("Caught expected exception: " + e.getMessage());
+            assertNotNull(e);
+        }
     }
 
     @Test
-    public void testInvalidateCache_success() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
-
-        HttpServletRequest request  = mockRequest();
-        KMS                kms      = newKms();
-        Response           response = kms.invalidateCache(TEST_KEY, request);
-
-        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
-        verify(mockAcls).assertAccess(
-                eq(Type.ROLLOVER), eq(user), eq(KMSOp.INVALIDATE_CACHE), eq(TEST_KEY), eq(CLIENT_IP));
-        verify(mockProvider).invalidateCache(TEST_KEY);
-        verify(mockProvider).flush();
-        verify(mockAudit).ok(user, KMSOp.INVALIDATE_CACHE, TEST_KEY, "");
-    }
+    public void testGetCurrentVersion() throws Exception {
+        String keyName = "testKey";
 
-    @Test
-    public void testInvalidateCache_deniedBeforeProviderCall() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
-
-        HttpServletRequest request = mockRequest();
-        doThrow(new AccessControlException("denied"))
-                .when(mockAcls).assertAccess(
-                        eq(Type.ROLLOVER), eq(user), eq(KMSOp.INVALIDATE_CACHE), eq(TEST_KEY), eq(CLIENT_IP));
-
-        KMS kms = newKms();
-        assertThrows(AccessControlException.class, () -> kms.invalidateCache(TEST_KEY, request));
-        verify(mockProvider, never()).invalidateCache(anyString());
+        // Mock request object
+        HttpServletRequest request = mock(HttpServletRequest.class);
+        lenient().when(request.getRemoteAddr()).thenReturn("127.0.0.1");
+        lenient().when(request.getRequestURI()).thenReturn("/kms/v1/keys/testKey");
+        Meter dummyMeter = mock(Meter.class);
+        Field meterField = KMSWebApp.class.getDeclaredField("adminCallsMeter");
+        meterField.setAccessible(true);
+        meterField.set(null, dummyMeter);
+
+        KMS kms = new KMS();
+
+        try {
+            kms.getCurrentVersion(keyName, request);
+            fail("Expected exception due to missing provider/user context");
+        } catch (Exception e) {
+            System.out.println("Caught expected exception: " + e.getMessage());
+            assertNotNull(e);
+        }
     }
 
     @Test
-    public void testGetKeyNames_successUsesNullKeyNameInAssertAccess() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
-
-        HttpServletRequest request = mockRequest();
-        List<String>       keys    = new ArrayList<>();
-        keys.add(TEST_KEY);
-        when(mockProvider.getKeys()).thenReturn(keys);
-
-        KMS      kms      = newKms();
-        Response response = kms.getKeyNames(request);
-
-        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
-        verify(mockAcls).assertAccess(
-                eq(Type.GET_KEYS), eq(user), eq(KMSOp.GET_KEYS), isNull(), eq(CLIENT_IP));
-        verify(mockProvider).getKeys();
-        verify(mockAudit).ok(user, KMSOp.GET_KEYS, "");
-    }
+    public void testGenerateDataKey() throws Exception {
+        String keyName = "testKey";
 
-    @Test
-    public void testGetKeyNames_deniedBeforeProviderCall() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
-
-        HttpServletRequest request = mockRequest();
-        doThrow(new AccessControlException("denied"))
-                .when(mockAcls).assertAccess(
-                        eq(Type.GET_KEYS), eq(user), eq(KMSOp.GET_KEYS), isNull(), eq(CLIENT_IP));
-
-        KMS kms = newKms();
-        assertThrows(AccessControlException.class, () -> kms.getKeyNames(request));
-        verify(mockProvider, never()).getKeys();
+        // Mock request object
+        HttpServletRequest request = mock(HttpServletRequest.class);
+        lenient().when(request.getRemoteAddr()).thenReturn("127.0.0.1");
+        lenient().when(request.getRequestURI()).thenReturn("/kms/v1/keys/testKey");
+        Meter dummyMeter = mock(Meter.class);
+        Field meterField = KMSWebApp.class.getDeclaredField("adminCallsMeter");
+        meterField.setAccessible(true);
+        meterField.set(null, dummyMeter);
+
+        KMS kms = new KMS();
+
+        try {
+            kms.generateDataKey(keyName, request);
+            fail("Expected exception due to missing provider/user context");
+        } catch (Exception e) {
+            System.out.println("Caught expected exception: " + e.getMessage());
+            assertNotNull(e);
+        }
     }
 
     @Test
-    public void testGetKeysMetadata_successUsesNullKeyNameInAssertAccess() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
-
-        HttpServletRequest request      = mockRequest();
-        List<String>       keyNamesList = new ArrayList<>();
-        keyNamesList.add(TEST_KEY);
-        KeyProvider.Metadata[] metas = {mockMetadata()};
-        when(mockProvider.getKeysMetadata(any(String[].class))).thenReturn(metas);
-
-        KMS      kms      = newKms();
-        Response response = kms.getKeysMetadata(keyNamesList, request);
-
-        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
-        verify(mockAcls).assertAccess(
-                eq(Type.GET_METADATA), eq(user), eq(KMSOp.GET_KEYS_METADATA), isNull(), eq(CLIENT_IP));
-        verify(mockProvider).getKeysMetadata(any(String[].class));
-        verify(mockAudit).ok(user, KMSOp.GET_KEYS_METADATA, "");
+    public void testGetKeyNames() throws Exception {
+        // Mock request object
+        HttpServletRequest request = mock(HttpServletRequest.class);
+        lenient().when(request.getRemoteAddr()).thenReturn("127.0.0.1");
+        lenient().when(request.getRequestURI()).thenReturn("/kms/v1/keys/testKey");
+        Meter dummyMeter = mock(Meter.class);
+        Field meterField = KMSWebApp.class.getDeclaredField("adminCallsMeter");
+        meterField.setAccessible(true);
+        meterField.set(null, dummyMeter);
+
+        KMS kms = new KMS();
+
+        try {
+            kms.getKeyNames(request);
+            fail("Expected exception due to missing provider/user context");
+        } catch (Exception e) {
+            System.out.println("Caught expected exception: " + e.getMessage());
+            assertNotNull(e);
+        }
     }
 
     @Test
-    public void testGetKeysMetadata_deniedBeforeProviderCall() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
-
-        HttpServletRequest request      = mockRequest();
-        List<String>       keyNamesList = new ArrayList<>();
-        keyNamesList.add(TEST_KEY);
+    void testDeleteKey_skippingAdminCallsMeter() throws Exception {
+        String               keyName  = "name";
+        UserGroupInformation mockUser = mock(UserGroupInformation.class);
 
-        doThrow(new AccessControlException("denied"))
-                .when(mockAcls).assertAccess(
-                        eq(Type.GET_METADATA), eq(user), eq(KMSOp.GET_KEYS_METADATA), isNull(), eq(CLIENT_IP));
+        HttpUserGroupInformation httpUserGroupInformation = mock(HttpUserGroupInformation.class);
 
-        KMS kms = newKms();
-        assertThrows(AccessControlException.class, () -> kms.getKeysMetadata(keyNamesList, request));
-        verify(mockProvider, never()).getKeysMetadata(any(String[].class));
+        // Set up mock request
+        HttpServletRequest request = mock(HttpServletRequest.class);
+        when(request.getRemoteAddr()).thenReturn("127.0.0.1");
+        lenient().when(request.getRequestURI()).thenReturn("/kms/v1/keys/testKey");
+
+        // Prepare a dummy Meter to avoid static call impact
+        Meter dummyMeter = mock(Meter.class);
+
+        // Set static adminCallsMeter in KMSWebApp using reflection
+        Field meterField = KMSWebApp.class.getDeclaredField("adminCallsMeter");
+        meterField.setAccessible(true);
+        meterField.set(null, dummyMeter);
+
+        // Create the KMS instance (internally calls KMSWebApp static methods)
+        KMS kms = new KMS();
+
+        // Run and expect exception (due to missing KMSWebApp dependencies like provider, user, etc.)
+        try {
+            kms.deleteKey(keyName, request);
+            fail("Expected exception due to missing dependencies like provider or UGI");
+        } catch (Exception e) {
+            System.out.println("Expected exception: " + e.getMessage());
+            assertNotNull(e);
+        }
     }
 
     @Test
-    public void testGenerateEncryptedKeys_successWithGenerateOp() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
-
-        HttpServletRequest  request = mockRequest();
-        EncryptedKeyVersion ekv     = mockEncryptedKeyVersion(TEST_KEY, TEST_KEY + "@0");
-        when(mockProvider.generateEncryptedKey(TEST_KEY)).thenReturn(ekv);
-
-        KMS kms = newKms();
-        Response response = kms.generateEncryptedKeys(
-                TEST_KEY, KMSRESTConstants.EEK_GENERATE, 1, request);
-
-        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
-        verify(mockAcls).assertAccess(
-                eq(Type.GENERATE_EEK), eq(user), eq(KMSOp.GENERATE_EEK), eq(TEST_KEY), eq(CLIENT_IP));
-        verify(mockProvider).generateEncryptedKey(TEST_KEY);
-        verify(mockAudit).ok(user, KMSOp.GENERATE_EEK, TEST_KEY, "");
-        verify(mockGenerateEEKMeter).mark();
+    void testCreateKeyWithOnlyInputValues() throws Exception {
+        // Prepare input map
+        Map<String, Object> jsonKey = new HashMap<>();
+        jsonKey.put("name", "testKey");
+        jsonKey.put("cipher", "AES");
+        jsonKey.put("length", 128);
+        jsonKey.put("description", "just a basic key");
+
+        // Mock request object
+        HttpServletRequest request = mock(HttpServletRequest.class);
+        lenient().when(request.getRemoteAddr()).thenReturn("127.0.0.1");
+        lenient().when(request.getRequestURI()).thenReturn("/kms/v1/keys/testKey");
+
+        Meter dummyMeter = mock(Meter.class);
+
+        Field meterField = KMSWebApp.class.getDeclaredField("adminCallsMeter");
+        meterField.setAccessible(true);
+        meterField.set(null, dummyMeter);
+
+        // Attempt call (expected to fail unless environment is injected)
+        KMS kms = new KMS();
+        try {
+            kms.createKey(jsonKey, request);
+            fail("Expected exception due to missing provider or user context");
+        } catch (Exception e) {
+            System.out.println("Caught expected exception: " + e.getMessage());
+        }
     }
 
     @Test
-    public void testGenerateEncryptedKeys_invalidEekOpFails() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
-
-        HttpServletRequest request = mockRequest();
-        KMS                kms     = newKms();
+    void testCreateKeyWithOnlyInputValues1() throws Exception {
+        // Prepare input map
+        Map<String, Object> jsonKey = new HashMap<>();
+        jsonKey.put("name", "testKey");
+        jsonKey.put("cipher", "AES");
+        jsonKey.put("length", 128);
+        jsonKey.put("description", "just a basic key");
 
-        assertThrows(IllegalArgumentException.class, () ->
-                kms.generateEncryptedKeys(TEST_KEY, "generateEncryptedKeys", 1, request));
-        verify(mockProvider, never()).generateEncryptedKey(anyString());
+        // Mock request object
+        HttpServletRequest request = mock(HttpServletRequest.class);
+        lenient().when(request.getRemoteAddr()).thenReturn("127.0.0.1");
+        lenient().when(request.getRequestURI()).thenReturn("/kms/v1/keys/testKey");
+
+        Meter dummyMeter = mock(Meter.class);
+
+        Field meterField = KMSWebApp.class.getDeclaredField("adminCallsMeter");
+        meterField.setAccessible(true);
+        meterField.set(null, dummyMeter);
+
+        // Attempt call (expected to fail unless environment is injected)
+        KMS kms = new KMS();
+        try {
+            kms.createKey(jsonKey, request);
+            fail("Expected exception due to missing provider or user context");
+        } catch (Exception e) {
+            System.out.println("Caught expected exception: " + e.getMessage());
+        }
     }
 
-    // reencryptEncryptedKeys
-
     @Test
-    public void testReencryptEncryptedKeys_success() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
-
-        HttpServletRequest request = mockRequest();
-        List<Map>          payload = buildReencryptPayload(TEST_KEY, 1);
-
-        KMS      kms      = newKms();
-        Response response = kms.reencryptEncryptedKeys(TEST_KEY, payload, request);
-
-        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
-        verify(mockAcls).assertAccess(
-                eq(Type.GENERATE_EEK), eq(user), eq(KMSOp.REENCRYPT_EEK_BATCH), eq(TEST_KEY), eq(CLIENT_IP));
-        verify(mockProvider).reencryptEncryptedKeys(any(List.class));
-        verify(mockAudit).ok(eq(user), eq(KMSOp.REENCRYPT_EEK_BATCH), eq(TEST_KEY), anyString());
-        verify(mockReencryptEEKBatchMeter).mark();
-    }
+    void testInvalidateCacheWithOnlyInputValues() throws Exception {
+        String keyName = "testKey";
 
-    @Test
-    public void testReencryptEncryptedKeys_deniedBeforeProviderCall() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
+        Meter dummyMeter = mock(Meter.class);
 
-        HttpServletRequest request = mockRequest();
-        List<Map>          payload = buildReencryptPayload(TEST_KEY, 1);
+        Field meterField = KMSWebApp.class.getDeclaredField("adminCallsMeter");
+        meterField.setAccessible(true);
+        meterField.set(null, dummyMeter);
 
-        doThrow(new AccessControlException("denied"))
-                .when(mockAcls).assertAccess(
-                        eq(Type.GENERATE_EEK), eq(user), eq(KMSOp.REENCRYPT_EEK_BATCH), eq(TEST_KEY), eq(CLIENT_IP));
+        HttpServletRequest request = mock(HttpServletRequest.class);
+        lenient().when(request.getRemoteAddr()).thenReturn("127.0.0.1");
 
-        KMS kms = newKms();
-        assertThrows(AccessControlException.class,
-                () -> kms.reencryptEncryptedKeys(TEST_KEY, payload, request));
-        verify(mockProvider, never()).reencryptEncryptedKeys(any(List.class));
-    }
+        KMS kms = new KMS();
 
-    @Test
-    public void testHandleEncryptedKeyOp_decryptSuccess() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
-
-        HttpServletRequest  request     = mockRequest();
-        String              versionName = TEST_KEY + "@0";
-        Map<String, Object> payload     = buildDecryptPayload(TEST_KEY);
-
-        KeyProvider.KeyVersion decrypted = createKeyVersion(TEST_KEY, versionName, new byte[] {9});
-        when(mockProvider.decryptEncryptedKey(any())).thenReturn(decrypted);
-
-        KMS kms = newKms();
-        Response response = kms.handleEncryptedKeyOp(
-                versionName, KMSRESTConstants.EEK_DECRYPT, payload, request);
-
-        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
-        verify(mockAcls).assertAccess(
-                eq(Type.DECRYPT_EEK), eq(user), eq(KMSOp.DECRYPT_EEK), eq(TEST_KEY), eq(CLIENT_IP));
-        verify(mockProvider).decryptEncryptedKey(any());
-        verify(mockAudit).ok(user, KMSOp.DECRYPT_EEK, TEST_KEY, "");
-        verify(mockDecryptEEKMeter).mark();
+        try {
+            kms.invalidateCache(keyName, request);
+            fail("Expected exception due to missing dependencies (provider/user)");
+        } catch (Exception e) {
+            System.out.println("Expected exception: " + e.getMessage());
+            assertNotNull(e);
+        }
     }
 
     @Test
-    public void testHandleEncryptedKeyOp_invalidEekOpFails() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
+    void testGetKey() throws Exception {
+        String keyName    = "testKey";
+        Meter  dummyMeter = mock(Meter.class);
 
-        HttpServletRequest  request = mockRequest();
-        Map<String, Object> payload = buildDecryptPayload(TEST_KEY);
-
-        KMS kms = newKms();
-        assertThrows(IllegalArgumentException.class, () ->
-                kms.handleEncryptedKeyOp(TEST_KEY + "@0", "bad_op", payload, request));
-    }
+        Field meterField = KMSWebApp.class.getDeclaredField("adminCallsMeter");
+        meterField.setAccessible(true);
+        meterField.set(null, dummyMeter);
 
-    @Test
-    public void testGenerateDataKey_success() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
-
-        HttpServletRequest     request = mockRequest();
-        EncryptedKeyVersion    ekv     = mockEncryptedKeyVersion(TEST_KEY, TEST_KEY + "@0");
-        KeyProvider.KeyVersion dek     = createKeyVersion(TEST_KEY, TEST_KEY + "@0", new byte[] {7});
-
-        when(mockProvider.generateEncryptedKey(TEST_KEY)).thenReturn(ekv);
-        when(mockProvider.decryptEncryptedKey(any())).thenReturn(dek);
-
-        KMS      kms      = newKms();
-        Response response = kms.generateDataKey(TEST_KEY, request);
-
-        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
-        verify(mockAcls).assertAccess(
-                eq(Type.GENERATE_EEK), eq(user), eq(KMSOp.GENERATE_EEK), eq(TEST_KEY), eq(CLIENT_IP));
-        verify(mockAcls).assertAccess(
-                eq(Type.DECRYPT_EEK), eq(user), eq(KMSOp.DECRYPT_EEK), eq(TEST_KEY), eq(CLIENT_IP));
-        verify(mockProvider).generateEncryptedKey(TEST_KEY);
-        verify(mockProvider).decryptEncryptedKey(any());
-    }
-
-    @Test
-    public void testGenerateDataKey_deniedOnGenerateBeforeDecrypt() throws Exception {
-        UserGroupInformation user = createTestUser();
-        setHttpUserInContext(user);
-
-        HttpServletRequest request = mockRequest();
-        doThrow(new AccessControlException("denied"))
-                .when(mockAcls).assertAccess(
-                        eq(Type.GENERATE_EEK), eq(user), eq(KMSOp.GENERATE_EEK), eq(TEST_KEY), eq(CLIENT_IP));
-
-        KMS kms = newKms();
-        IOException ex = assertThrows(IOException.class, () -> kms.generateDataKey(TEST_KEY, request));
-        assertInstanceOf(AccessControlException.class, ex.getCause());
-        verify(mockProvider, never()).generateEncryptedKey(anyString());
+        KMS                kms     = new KMS();
+        HttpServletRequest request = mock(HttpServletRequest.class);
+        lenient().when(request.getRemoteAddr()).thenReturn("127.0.0.1");
+        lenient().when(request.getRequestURI()).thenReturn("/kms/v1/keys/testKey");
+
+        try {
+            kms.getKey(keyName, request);
+            fail("Expected exception due to missing dependencies (provider/user)");
+        } catch (Exception e) {
+            System.out.println("Expected exception: " + e.getMessage());
+            assertNotNull(e);
+        }
     }
 
-    // Validation and helpers
-
     @Test
-    public void testValidateKeyName_valid() throws Exception {
-        KMS    kms    = newKms();
-        Method method = KMS.class.getDeclaredMethod("validateKeyName", String.class);
+    void testValidateKeyName_valid_reflection() throws Exception {
+        String validKeyName = "ValidKey_123";
+        KMS    kms          = new KMS();
+        Method method       = KMS.class.getDeclaredMethod("validateKeyName", String.class);
         method.setAccessible(true);
+
         assertDoesNotThrow(() -> method.invoke(kms, "ValidKey_123"));
     }
 
     @Test
-    public void testValidateKeyName_invalid() throws Exception {
-        KMS    kms    = newKms();
+    void testValidateKeyName_invalid_reflection() throws Exception {
+        KMS    kms    = new KMS();
         Method method = KMS.class.getDeclaredMethod("validateKeyName", String.class);
         method.setAccessible(true);
 
-        InvocationTargetException ex = assertThrows(InvocationTargetException.class, () ->
-                method.invoke(kms, "!invalid-key"));
+        InvocationTargetException ex = assertThrows(InvocationTargetException.class, () -> {
+            method.invoke(kms, "!invalid-key");
+        });
+
         assertInstanceOf(IllegalArgumentException.class, ex.getCause());
     }
 
     @Test
-    public void testGetKeyURI_buildsExpectedPath() throws Exception {
+    void testGetKeyURI_reflection() throws Exception {
         Method method = KMS.class.getDeclaredMethod("getKeyURI", String.class, String.class);
         method.setAccessible(true);
-        URI result = (URI) method.invoke(null, "v1", TEST_KEY);
-        assertEquals("v1/key/testKey", result.toString());
-    }
 
-    @Test
-    public void testRemoveKeyMaterial_stripsBytes() throws Exception {
-        KeyProvider.KeyVersion original = createKeyVersion("key1", "v1", "secret".getBytes());
-        Method                 method   = KMS.class.getDeclaredMethod("removeKeyMaterial", KeyProvider.KeyVersion.class);
-        method.setAccessible(true);
+        URI result = (URI) method.invoke(null, "v1", "testKey");
 
-        KeyProvider.KeyVersion result = (KeyProvider.KeyVersion) method.invoke(null, original);
-        assertEquals("key1", result.getName());
-        assertEquals("v1", result.getVersionName());
-        assertNull(result.getMaterial());
+        assertEquals("v1/key/testKey", result.toString()); // ✅ expected value
     }
 
     @Test
-    public void testCreateKey_withoutUserFails() throws Exception {
-        HttpServletRequest  request = mockRequest();
-        Map<String, Object> jsonKey = baseKeyJson(TEST_KEY);
-        KMS                 kms     = newKms();
-
-        assertThrows(NullPointerException.class, () -> kms.createKey(jsonKey, request));
-    }
-
-    // Helpers
-
-    private KMS newKms() throws Exception {
-        return new KMS();
-    }
-
-    private UserGroupInformation createTestUser() throws IOException {
-        return UserGroupInformation.createRemoteUser("testuser");
-    }
-
-    private HttpServletRequest mockRequest() {
-        HttpServletRequest request = mock(HttpServletRequest.class);
-        lenient().when(request.getRemoteAddr()).thenReturn(CLIENT_IP);
-        return request;
-    }
-
-    private Map<String, Object> baseKeyJson(String keyName) {
-        Map<String, Object> jsonKey = new HashMap<>();
-        jsonKey.put(KMSRESTConstants.NAME_FIELD, keyName);
-        jsonKey.put(KMSRESTConstants.CIPHER_FIELD, "AES");
-        jsonKey.put(KMSRESTConstants.LENGTH_FIELD, 128);
-        jsonKey.put(KMSRESTConstants.DESCRIPTION_FIELD, "test key");
-        return jsonKey;
-    }
-
-    private List<Map> buildReencryptPayload(String keyName, int count) {
-        List<Map> payload = new ArrayList<>();
-        for (int i = 0; i < count; i++) {
-            String              versionName = keyName + "@" + i;
-            Map<String, Object> encInner    = new HashMap<>();
-            encInner.put(KMSRESTConstants.VERSION_NAME_FIELD, versionName);
-            encInner.put(KMSRESTConstants.MATERIAL_FIELD,
-                    Base64.getEncoder().encodeToString("encMat".getBytes()));
-
-            Map<String, Object> entry = new HashMap<>();
-            entry.put(KMSRESTConstants.VERSION_NAME_FIELD, versionName);
-            entry.put(KMSRESTConstants.IV_FIELD,
-                    Base64.getEncoder().encodeToString("12345678".getBytes()));
-            entry.put(KMSRESTConstants.ENCRYPTED_KEY_VERSION_FIELD, encInner);
-            payload.add(entry);
-        }
-        return payload;
-    }
-
-    private Map<String, Object> buildDecryptPayload(String keyName) {
-        Map<String, Object> payload = new HashMap<>();
-        payload.put(KMSRESTConstants.NAME_FIELD, keyName);
-        payload.put(KMSRESTConstants.IV_FIELD,
-                Base64.getEncoder().encodeToString("12345678".getBytes()));
-        payload.put(KMSRESTConstants.MATERIAL_FIELD,
-                Base64.getEncoder().encodeToString("encMaterial".getBytes()));
-        return payload;
-    }
-
-    private KeyProvider.Metadata mockMetadata() {
-        KeyProvider.Metadata metadata = mock(KeyProvider.Metadata.class);
-        when(metadata.getCipher()).thenReturn("AES/CTR/NoPadding");
-        when(metadata.getBitLength()).thenReturn(128);
-        when(metadata.getDescription()).thenReturn("test key");
-        when(metadata.getAttributes()).thenReturn(null);
-        when(metadata.getCreated()).thenReturn(new Date());
-        when(metadata.getVersions()).thenReturn(1);
-        return metadata;
-    }
-
-    private EncryptedKeyVersion mockEncryptedKeyVersion(String keyName, String versionName)
-            throws Exception {
-        KeyProvider.KeyVersion nested = createKeyVersion(keyName, versionName, new byte[] {1, 2, 3});
-        EncryptedKeyVersion    ekv    = mock(EncryptedKeyVersion.class);
-        lenient().when(ekv.getEncryptionKeyName()).thenReturn(keyName);
-        when(ekv.getEncryptionKeyVersionName()).thenReturn(versionName);
-        when(ekv.getEncryptedKeyIv()).thenReturn(new byte[8]);
-        when(ekv.getEncryptedKeyVersion()).thenReturn(nested);
-        return ekv;
-    }
-
-    private static KeyProvider.KeyVersion createKeyVersion(String name, String versionName, byte[] material)
-            throws Exception {
-        Constructor<?> ctor = KeyProvider.KeyVersion.class.getDeclaredConstructor(
-                String.class, String.class, byte[].class);
+    void testRemoveKeyMaterial_reflection() throws Exception {
+        Constructor<?> ctor = KeyProvider.KeyVersion.class.getDeclaredConstructor(String.class, String.class, byte[].class);
         ctor.setAccessible(true);
-        return (KeyProvider.KeyVersion) ctor.newInstance(name, versionName, material);
-    }
-
-    private static void setHttpUserInContext(UserGroupInformation ugi) throws Exception {
-        Field ugiTlField = DelegationTokenAuthenticationFilter.class.getDeclaredField("UGI_TL");
-        ugiTlField.setAccessible(true);
-        @SuppressWarnings("unchecked")
-        ThreadLocal<UserGroupInformation> ugiTl =
-                (ThreadLocal<UserGroupInformation>) ugiTlField.get(null);
-        ugiTl.set(ugi);
-    }
-
-    private static void clearHttpUserInContext() throws Exception {
-        Field ugiTlField = DelegationTokenAuthenticationFilter.class.getDeclaredField("UGI_TL");
-        ugiTlField.setAccessible(true);
-        @SuppressWarnings("unchecked")
-        ThreadLocal<UserGroupInformation> ugiTl =
-                (ThreadLocal<UserGroupInformation>) ugiTlField.get(null);
-        ugiTl.remove();
-    }
 
-    private static void setMdcContext(UserGroupInformation ugi, String url) throws Exception {
-        Field dataTlField = KMSMDCFilter.class.getDeclaredField("DATA_TL");
-        dataTlField.setAccessible(true);
-        @SuppressWarnings("unchecked")
-        ThreadLocal<Object> tl = (ThreadLocal<Object>) dataTlField.get(null);
+        KeyProvider.KeyVersion original = (KeyProvider.KeyVersion) ctor.newInstance("key1", "v1", "secret".getBytes());
 
-        Class<?> dataClass = Class.forName(
-                "org.apache.hadoop.crypto.key.kms.server.KMSMDCFilter$Data");
-        Constructor<?> ctor = dataClass.getDeclaredConstructor(
-                UserGroupInformation.class, String.class, String.class);
-        ctor.setAccessible(true);
-        Object data = ctor.newInstance(ugi, "POST", url);
-        tl.set(data);
-    }
-
-    private static void clearMdcContext() throws Exception {
-        Field dataTlField = KMSMDCFilter.class.getDeclaredField("DATA_TL");
-        dataTlField.setAccessible(true);
-        @SuppressWarnings("unchecked")
-        ThreadLocal<?> tl = (ThreadLocal<?>) dataTlField.get(null);
-        tl.remove();
-    }
-
-    private static Map<String, Object> snapshotMutableKmsWebAppStatics() throws Exception {
-        Map<String, Object> snapshot = new HashMap<>();
-        for (String fieldName : KMS_WEB_APP_MUTABLE_STATIC_FIELDS) {
-            snapshot.put(fieldName, getStaticField(KMSWebApp.class, fieldName));
-        }
-        return snapshot;
-    }
+        Method method = KMS.class.getDeclaredMethod("removeKeyMaterial", KeyProvider.KeyVersion.class);
+        method.setAccessible(true);
 
-    private static void restoreKmsWebAppStatics(Map<String, Object> snapshot) throws Exception {
-        for (Map.Entry<String, Object> entry : snapshot.entrySet()) {
-            setStaticField(KMSWebApp.class, entry.getKey(), entry.getValue());
-        }
-    }
+        KeyProvider.KeyVersion result = (KeyProvider.KeyVersion) method.invoke(null, original);
 
-    private static Object getStaticField(Class<?> clazz, String fieldName) throws Exception {
-        Field field = clazz.getDeclaredField(fieldName);
-        field.setAccessible(true);
-        return field.get(null);
+        assertEquals("key1", result.getName());
+        assertEquals("v1", result.getVersionName());
+        assertNull(result.getMaterial());
     }
 
     private static void setStaticField(Class<?> clazz, String fieldName, Object value) throws Exception {