From b30fe7b38d3eceab45205c43194bd825895c7dbf Mon Sep 17 00:00:00 2001
From: Endi Sukma Dewata <edewata@redhat.com>
Date: Wed, 10 Oct 2012 04:38:05 -0500
Subject: [PATCH] Added ACLInterceptor.

Previously ACL checking was done in PKIRealm by matching the URL.
This code has been replaced by ACLInterceptor which will intercept
RESTEasy method invocations. This allows more precise mapping of
REST methods to ACL entries in acl.ldif.

Ticket #287
---
 base/ca/shared/webapps/ca/WEB-INF/auth.properties  |  18 +-
 .../ca/CertificateAuthorityApplication.java        |   4 +
 .../netscape/certsrv/account/AccountResource.java  |   4 +
 .../com/netscape/certsrv/acls/ACLInterceptor.java  | 154 ++++++++++++++
 .../AccountResource.java => acls/ACLMapping.java}  |  20 +-
 .../netscape/certsrv/cert/CertRequestResource.java |   2 +
 .../com/netscape/certsrv/cert/CertResource.java    |   4 +
 .../com/netscape/certsrv/group/GroupResource.java  |   3 +
 .../netscape/certsrv/key/KeyRequestResource.java   |   2 +
 .../src/com/netscape/certsrv/key/KeyResource.java  |   3 +
 .../certsrv/system/SecurityDomainResource.java     |   3 +
 .../com/netscape/certsrv/user/UserResource.java    |   3 +
 .../src/com/netscape/cmscore/realm/PKIRealm.java   | 221 ---------------------
 .../kra/shared/webapps/kra/WEB-INF/auth.properties |  16 +-
 .../kra/KeyRecoveryAuthorityApplication.java       |   3 +
 .../shared/webapps/ocsp/WEB-INF/auth.properties    |  12 +-
 .../src/com/netscape/ocsp/OCSPApplication.java     |   4 +
 .../tks/shared/webapps/tks/WEB-INF/auth.properties |  12 +-
 base/tks/src/com/netscape/tks/TKSApplication.java  |   4 +
 19 files changed, 229 insertions(+), 263 deletions(-)
 create mode 100644 base/common/src/com/netscape/certsrv/acls/ACLInterceptor.java
 copy base/common/src/com/netscape/certsrv/{account/AccountResource.java => acls/ACLMapping.java} (76%)

diff --git a/base/ca/shared/webapps/ca/WEB-INF/auth.properties b/base/ca/shared/webapps/ca/WEB-INF/auth.properties
index 116bc94bfee11c386151be9e69fa6a1e3900c3b5..08f5bea504dd16ceec3d2c08150e6cac7a18d597 100644
--- a/base/ca/shared/webapps/ca/WEB-INF/auth.properties
+++ b/base/ca/shared/webapps/ca/WEB-INF/auth.properties
@@ -1,13 +1,13 @@
 # Restful API auth/authz mapping info
 #
 # Format:
-# <Rest API URL> = <ACL Resource ID>,<ACL resource operation>
-# ex:      /ca/pki/users = certServer.ca.users,read
+# <ACL Mapping> = <ACL Resource ID>,<ACL Resource Operation>
+# ex:      admin.users = certServer.ca.users,read
 
-/ca/rest/account/login = certServer.ca.account,login
-/ca/rest/account/logout = certServer.ca.account,logout
-/ca/rest/admin/users = certServer.ca.users,execute
-/ca/rest/admin/groups = certServer.ca.groups,execute
-/ca/rest/agent/certrequests = certServer.ca.certrequests,execute
-/ca/rest/agent/certs = certServer.ca.certs,execute
-/ca/rest/securityDomain/installToken = certServer.securitydomain.domainxml,read
+account.login = certServer.ca.account,login
+account.logout = certServer.ca.account,logout
+admin.users = certServer.ca.users,execute
+admin.groups = certServer.ca.groups,execute
+agent.certrequests = certServer.ca.certrequests,execute
+agent.certs = certServer.ca.certs,execute
+securityDomain.installToken = certServer.securitydomain.domainxml,read
diff --git a/base/ca/src/com/netscape/ca/CertificateAuthorityApplication.java b/base/ca/src/com/netscape/ca/CertificateAuthorityApplication.java
index 42fd439de59ae8223656b4797e60a1e93c9f5f69..bc6dd71a6ccaa8db16a91ea3cd5ab45326776acc 100644
--- a/base/ca/src/com/netscape/ca/CertificateAuthorityApplication.java
+++ b/base/ca/src/com/netscape/ca/CertificateAuthorityApplication.java
@@ -5,6 +5,7 @@ import java.util.Set;
 
 import javax.ws.rs.core.Application;
 
+import com.netscape.certsrv.acls.ACLInterceptor;
 import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.base.EBaseException;
 import com.netscape.certsrv.base.IConfigStore;
@@ -79,6 +80,9 @@ public class CertificateAuthorityApplication extends Application {
 
         // exception mapper
         classes.add(PKIException.Mapper.class);
+
+        // ACL interceptor
+        singletons.add(new ACLInterceptor());
     }
 
     public Set<Class<?>> getClasses() {
diff --git a/base/common/src/com/netscape/certsrv/account/AccountResource.java b/base/common/src/com/netscape/certsrv/account/AccountResource.java
index ee40b24a8d5fdebbbb54147f3e06727e35d8c60d..a69a3d122e1d887b7a8d081e6fb3f477fa1715e9 100644
--- a/base/common/src/com/netscape/certsrv/account/AccountResource.java
+++ b/base/common/src/com/netscape/certsrv/account/AccountResource.java
@@ -21,6 +21,8 @@ package com.netscape.certsrv.account;
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
 
+import com.netscape.certsrv.acls.ACLMapping;
+
 /**
  * @author Endi S. Dewata
  */
@@ -29,9 +31,11 @@ public interface AccountResource {
 
     @GET
     @Path("login")
+    @ACLMapping("account.login")
     public void login();
 
     @GET
     @Path("logout")
+    @ACLMapping("account.logout")
     public void logout();
 }
diff --git a/base/common/src/com/netscape/certsrv/acls/ACLInterceptor.java b/base/common/src/com/netscape/certsrv/acls/ACLInterceptor.java
new file mode 100644
index 0000000000000000000000000000000000000000..bcb0b80a2fff19db4641c6518a89b937c9490644
--- /dev/null
+++ b/base/common/src/com/netscape/certsrv/acls/ACLInterceptor.java
@@ -0,0 +1,154 @@
+//--- BEGIN COPYRIGHT BLOCK ---
+//This program is free software; you can redistribute it and/or modify
+//it under the terms of the GNU General Public License as published by
+//the Free Software Foundation; version 2 of the License.
+//
+//This program is distributed in the hope that it will be useful,
+//but WITHOUT ANY WARRANTY; without even the implied warranty of
+//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//GNU General Public License for more details.
+//
+//You should have received a copy of the GNU General Public License along
+//with this program; if not, write to the Free Software Foundation, Inc.,
+//51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+//(C) 2012 Red Hat, Inc.
+//All rights reserved.
+//--- END COPYRIGHT BLOCK ---
+package com.netscape.certsrv.acls;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.security.Principal;
+import java.util.Properties;
+
+import javax.servlet.ServletContext;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+import javax.ws.rs.ext.Provider;
+
+import org.jboss.resteasy.annotations.interception.Precedence;
+import org.jboss.resteasy.annotations.interception.ServerInterceptor;
+import org.jboss.resteasy.core.ResourceMethod;
+import org.jboss.resteasy.core.ServerResponse;
+import org.jboss.resteasy.spi.Failure;
+import org.jboss.resteasy.spi.HttpRequest;
+import org.jboss.resteasy.spi.interception.PreProcessInterceptor;
+
+import com.netscape.certsrv.apps.CMS;
+import com.netscape.certsrv.authentication.IAuthToken;
+import com.netscape.certsrv.authorization.AuthzToken;
+import com.netscape.certsrv.authorization.EAuthzAccessDenied;
+import com.netscape.certsrv.authorization.IAuthzSubsystem;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.cmscore.realm.PKIPrincipal;
+
+
+/**
+ * @author Endi S. Dewata
+ */
+@Provider
+@ServerInterceptor
+@Precedence("SECURITY")
+public class ACLInterceptor implements PreProcessInterceptor {
+
+    Properties authProperties;
+
+    @Context
+    ServletContext servletContext;
+
+    @Context
+    SecurityContext securityContext;
+
+    public synchronized void loadAuthProperties() throws IOException {
+
+        if (authProperties != null) return;
+
+        URL url = servletContext.getResource("/WEB-INF/auth.properties");
+        authProperties = new Properties();
+        authProperties.load(url.openStream());
+    }
+
+    @Override
+    public ServerResponse preProcess(
+            HttpRequest request,
+            ResourceMethod resourceMethod
+        ) throws Failure, WebApplicationException {
+
+        // Get ACL mapping for the method.
+        Method method = resourceMethod.getMethod();
+        ACLMapping aclMapping = method.getAnnotation(ACLMapping.class);
+
+        // If not available, get ACL mapping for the class.
+        if (aclMapping == null) {
+            Class<?> clazz = method.getDeclaringClass();
+            aclMapping = clazz.getAnnotation(ACLMapping.class);
+        }
+
+        // If still not available, it's unprotected, allow request.
+        if (aclMapping == null) return null;
+
+        Principal principal = securityContext.getUserPrincipal();
+
+        // If unauthenticated, reject request.
+        if (principal == null) {
+            throw new WebApplicationException(Response.Status.FORBIDDEN);
+        }
+
+        // If unrecognized principal, reject request.
+        if (!(principal instanceof PKIPrincipal)) {
+            throw new WebApplicationException(Response.Status.FORBIDDEN);
+        }
+
+        PKIPrincipal pkiPrincipal = (PKIPrincipal)principal;
+        IAuthToken authToken = pkiPrincipal.getAuthToken();
+
+        // If missing auth token, reject request.
+        if (authToken == null) {
+            throw new WebApplicationException(Response.Status.FORBIDDEN);
+        }
+
+        try {
+            loadAuthProperties();
+
+            String name = aclMapping.value();
+            String value = authProperties.getProperty(name);
+
+            // If no property defined, allow request.
+            if (value == null) return null;
+
+            String values[] = value.split(",");
+
+            // If invalid mapping, reject request.
+            if (values.length != 2) {
+                throw new WebApplicationException(Response.Status.FORBIDDEN);
+            }
+
+            // Check authorization.
+            IAuthzSubsystem mAuthz = (IAuthzSubsystem) CMS.getSubsystem(CMS.SUBSYSTEM_AUTHZ);
+            AuthzToken authzToken = mAuthz.authorize(
+                    "DirAclAuthz",
+                    authToken,
+                    values[0], // resource
+                    values[1]); // operation
+
+            // If not authorized, reject request.
+            if (authzToken == null) {
+                throw new WebApplicationException(Response.Status.FORBIDDEN);
+            }
+
+        } catch (EAuthzAccessDenied e) {
+            throw new WebApplicationException(Response.Status.FORBIDDEN);
+
+        } catch (IOException|EBaseException e) {
+            e.printStackTrace();
+            throw new Failure(e);
+        }
+
+        // Allow request.
+        return null;
+    }
+}
diff --git a/base/common/src/com/netscape/certsrv/account/AccountResource.java b/base/common/src/com/netscape/certsrv/acls/ACLMapping.java
similarity index 76%
copy from base/common/src/com/netscape/certsrv/account/AccountResource.java
copy to base/common/src/com/netscape/certsrv/acls/ACLMapping.java
index ee40b24a8d5fdebbbb54147f3e06727e35d8c60d..a78ffaee0ef298c0fffc85f5b23da72e4d950954 100644
--- a/base/common/src/com/netscape/certsrv/account/AccountResource.java
+++ b/base/common/src/com/netscape/certsrv/acls/ACLMapping.java
@@ -16,22 +16,16 @@
 // All rights reserved.
 // --- END COPYRIGHT BLOCK ---
 
-package com.netscape.certsrv.account;
+package com.netscape.certsrv.acls;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
 
 /**
  * @author Endi S. Dewata
  */
-@Path("account")
-public interface AccountResource {
-
-    @GET
-    @Path("login")
-    public void login();
-
-    @GET
-    @Path("logout")
-    public void logout();
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ACLMapping {
+    public String value();
 }
diff --git a/base/common/src/com/netscape/certsrv/cert/CertRequestResource.java b/base/common/src/com/netscape/certsrv/cert/CertRequestResource.java
index 1a186f6275a0e6b875064f1f41a4b6979522b9ac..2a465ce56393ab1c98690f43625d7430ac6e4d70 100644
--- a/base/common/src/com/netscape/certsrv/cert/CertRequestResource.java
+++ b/base/common/src/com/netscape/certsrv/cert/CertRequestResource.java
@@ -28,6 +28,7 @@ import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 
+import com.netscape.certsrv.acls.ACLMapping;
 import com.netscape.certsrv.request.RequestId;
 
 @Path("")
@@ -62,6 +63,7 @@ public interface CertRequestResource {
     @GET
     @Path("agent/certrequests/{id}")
     @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    @ACLMapping("agent.certrequests")
     public CertReviewResponse reviewRequest(@PathParam("id") RequestId id);
 
     // Enrollment - used to test integration with a browser
diff --git a/base/common/src/com/netscape/certsrv/cert/CertResource.java b/base/common/src/com/netscape/certsrv/cert/CertResource.java
index 1d5958824298dd201a6aba882bd29dd89b36635e..53e06ca6ebdf48ce2b71395648555ef4b7df78e5 100644
--- a/base/common/src/com/netscape/certsrv/cert/CertResource.java
+++ b/base/common/src/com/netscape/certsrv/cert/CertResource.java
@@ -10,6 +10,7 @@ import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 
+import com.netscape.certsrv.acls.ACLMapping;
 import com.netscape.certsrv.dbs.certdb.CertId;
 
 @Path("")
@@ -44,17 +45,20 @@ public interface CertResource {
     @Path("agent/certs/{id}/revoke-ca")
     @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
     @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    @ACLMapping("agent.certs")
     public CertRequestInfo revokeCACert(@PathParam("id") CertId id, CertRevokeRequest request);
 
     @POST
     @Path("agent/certs/{id}/revoke")
     @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
     @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    @ACLMapping("agent.certs")
     public CertRequestInfo revokeCert(@PathParam("id") CertId id, CertRevokeRequest request);
 
     @POST
     @Path("agent/certs/{id}/unrevoke")
     @Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
     @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    @ACLMapping("agent.certs")
     public CertRequestInfo unrevokeCert(@PathParam("id") CertId id, CertUnrevokeRequest request);
 }
diff --git a/base/common/src/com/netscape/certsrv/group/GroupResource.java b/base/common/src/com/netscape/certsrv/group/GroupResource.java
index e0110e6a8692035609d3f3aeca84eb320b2d4723..17728dd13fbd9bbf2b653f4eb0eee61f316f3266 100644
--- a/base/common/src/com/netscape/certsrv/group/GroupResource.java
+++ b/base/common/src/com/netscape/certsrv/group/GroupResource.java
@@ -31,10 +31,13 @@ import javax.ws.rs.core.Response;
 
 import org.jboss.resteasy.annotations.ClientResponseType;
 
+import com.netscape.certsrv.acls.ACLMapping;
+
 /**
  * @author Endi S. Dewata
  */
 @Path("admin/groups")
+@ACLMapping("admin.groups")
 public interface GroupResource {
 
     @GET
diff --git a/base/common/src/com/netscape/certsrv/key/KeyRequestResource.java b/base/common/src/com/netscape/certsrv/key/KeyRequestResource.java
index 356fd1569c391b840ff2998a3009964a03367951..9f1ffbe023d73d82e959f35c582eae20012de2bc 100644
--- a/base/common/src/com/netscape/certsrv/key/KeyRequestResource.java
+++ b/base/common/src/com/netscape/certsrv/key/KeyRequestResource.java
@@ -10,9 +10,11 @@ import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 
+import com.netscape.certsrv.acls.ACLMapping;
 import com.netscape.certsrv.request.RequestId;
 
 @Path("agent/keyrequests")
+@ACLMapping("agent.keyrequests")
 public interface KeyRequestResource {
 
     public final String SYMMETRIC_KEY_TYPE = "symmetricKey";
diff --git a/base/common/src/com/netscape/certsrv/key/KeyResource.java b/base/common/src/com/netscape/certsrv/key/KeyResource.java
index 50fe82cc313585cbf5c033bd00aff22451779a28..da7f2203121072a593c2ad300f732b1da5adba1c 100644
--- a/base/common/src/com/netscape/certsrv/key/KeyResource.java
+++ b/base/common/src/com/netscape/certsrv/key/KeyResource.java
@@ -9,8 +9,11 @@ import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 
+import com.netscape.certsrv.acls.ACLMapping;
+
 
 @Path("agent/keys")
+@ACLMapping("agent.keys")
 public interface KeyResource {
 
     @GET
diff --git a/base/common/src/com/netscape/certsrv/system/SecurityDomainResource.java b/base/common/src/com/netscape/certsrv/system/SecurityDomainResource.java
index 1805d15c4d6c6767a54c20db3b27fbc9224ebb75..b34d9fe13715ab85fded77c7d90db82e0a89bf6d 100644
--- a/base/common/src/com/netscape/certsrv/system/SecurityDomainResource.java
+++ b/base/common/src/com/netscape/certsrv/system/SecurityDomainResource.java
@@ -23,6 +23,8 @@ import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 
+import com.netscape.certsrv.acls.ACLMapping;
+
 /**
  * @author alee
  */
@@ -32,6 +34,7 @@ public interface SecurityDomainResource {
     @GET
     @Path("installToken")
     @Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+    @ACLMapping("securityDomain.installToken")
     public InstallToken getInstallToken(
             @QueryParam("hostname") String hostname,
             @QueryParam("subsystem") String subsystem);
diff --git a/base/common/src/com/netscape/certsrv/user/UserResource.java b/base/common/src/com/netscape/certsrv/user/UserResource.java
index 4a837165f03018c836d4a47c962d7f043622a776..e72bb0cefbc204aea7da51ea1f7e4da3fde5960f 100644
--- a/base/common/src/com/netscape/certsrv/user/UserResource.java
+++ b/base/common/src/com/netscape/certsrv/user/UserResource.java
@@ -31,10 +31,13 @@ import javax.ws.rs.core.Response;
 
 import org.jboss.resteasy.annotations.ClientResponseType;
 
+import com.netscape.certsrv.acls.ACLMapping;
+
 /**
  * @author Endi S. Dewata
  */
 @Path("admin/users")
+@ACLMapping("admin.users")
 public interface UserResource {
 
     @GET
diff --git a/base/common/src/com/netscape/cmscore/realm/PKIRealm.java b/base/common/src/com/netscape/cmscore/realm/PKIRealm.java
index 9b4b97c2a5e0dfbb78775f5b46ec41c7a4e839c2..5e9ae4116ba707e6bbdb05b668e6a235e7b2748e 100644
--- a/base/common/src/com/netscape/cmscore/realm/PKIRealm.java
+++ b/base/common/src/com/netscape/cmscore/realm/PKIRealm.java
@@ -1,31 +1,19 @@
 package com.netscape.cmscore.realm;
 
-import java.io.IOException;
-import java.io.InputStream;
 import java.security.Principal;
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.List;
-import java.util.Properties;
-
-import javax.servlet.http.HttpServletResponse;
 
 import netscape.security.x509.X509CertImpl;
 
-import org.apache.catalina.Context;
-import org.apache.catalina.LifecycleException;
-import org.apache.catalina.connector.Request;
-import org.apache.catalina.connector.Response;
-import org.apache.catalina.deploy.SecurityConstraint;
 import org.apache.catalina.realm.RealmBase;
 
 import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.authentication.IAuthManager;
 import com.netscape.certsrv.authentication.IAuthSubsystem;
 import com.netscape.certsrv.authentication.IAuthToken;
-import com.netscape.certsrv.authorization.AuthzToken;
-import com.netscape.certsrv.authorization.IAuthzSubsystem;
 import com.netscape.certsrv.usrgrp.EUsrGrpException;
 import com.netscape.certsrv.usrgrp.IGroup;
 import com.netscape.certsrv.usrgrp.IUGSubsystem;
@@ -44,27 +32,6 @@ import com.netscape.cmscore.authentication.PasswdUserDBAuthentication;
 
 public class PKIRealm extends RealmBase {
 
-    public final static String PROP_AUTH_FILE_PATH = "/WEB-INF/auth.properties";
-    public final static int EXPRESSION_SIZE = 2;
-
-    Properties authzProperties;
-
-    public PKIRealm() {
-        logDebug("Creating PKI realm");
-    }
-
-    @Override
-    protected void initInternal() throws LifecycleException {
-        logDebug("Initializing PKI realm");
-        super.initInternal();
-    }
-
-    @Override
-    protected void startInternal() throws LifecycleException {
-        logDebug("Starting PKI realm");
-        super.startInternal();
-    }
-
     @Override
     protected String getName() {
         return "PKIRealm";
@@ -180,194 +147,6 @@ public class PKIRealm extends RealmBase {
         return null;
     }
 
-    /**
-     * Perform access control based on the specified authorization constraint.
-     * Return <code>true</code> if this constraint is satisfied and processing
-     * should continue, or <code>false</code> otherwise.
-     * override to check for custom PKI ACL's authz permissions.
-     *
-     * @param request Request we are processing
-     * @param response Response we are creating
-     * @param constraints Security constraint we are enforcing
-     * @param context The Context to which client of this class is attached.
-     *
-     * @exception IOException if an input/output error occurs
-     */
-    @Override
-    public boolean hasResourcePermission(Request request,
-            Response response,
-            SecurityConstraint[] constraints,
-            Context context)
-            throws IOException {
-
-        String requestURI = request.getDecodedRequestURI();
-        logDebug("Checking permission: "+requestURI);
-
-        boolean allowed = super.hasResourcePermission(request, response, constraints, context);
-        logDebug("Resource permission: "+allowed);
-
-        if (allowed) {
-            allowed = checkACL(request, response, constraints, context);
-            logDebug("ACL permission: "+allowed);
-        }
-
-        if (!allowed) {
-            response.sendError(HttpServletResponse.SC_FORBIDDEN, sm.getString("realmBase.forbidden"));
-        }
-
-        return allowed;
-    }
-
-    public boolean checkACL(Request request,
-            Response response,
-            SecurityConstraint[] constraints,
-            Context context) {
-
-        try {
-            loadAuthzProperties(context);
-            if (!hasAuthzProperties()) return false;
-
-            String requestURI = request.getDecodedRequestURI();
-            String match = getACLEntry(requestURI);
-            if (match == null) return false;
-
-            logDebug("ACL: "+match);
-            String[] authzParams = match.split("\\,");
-
-            String resource = null;
-            String operation = null;
-
-            if (authzParams.length >= EXPRESSION_SIZE) {
-                resource = authzParams[0];
-                operation = authzParams[1];
-
-                if (resource != null) {
-                    resource = resource.trim();
-                }
-
-                if (operation != null) {
-                    operation = operation.trim();
-                }
-            }
-
-            Principal principal = request.getUserPrincipal();
-            if (principal instanceof PKIPrincipal) {
-                PKIPrincipal pkiPrincipal = (PKIPrincipal)principal;
-                IAuthToken authToken = pkiPrincipal.getAuthToken();
-
-                logDebug("Auth token:");
-                Enumeration<String> names = authToken.getElements();
-                while (names.hasMoreElements()) {
-                    String name = names.nextElement();
-                    Object value = authToken.get(name);
-                    logDebug("  " + name +": " + value);
-                }
-
-                logDebug("Resource: " + resource);
-                logDebug("Operation: " + operation);
-
-                IAuthzSubsystem mAuthz = (IAuthzSubsystem) CMS.getSubsystem(CMS.SUBSYSTEM_AUTHZ);
-                AuthzToken authzToken = mAuthz.authorize("DirAclAuthz", authToken, resource, operation);
-                if (authzToken != null) return true;
-            }
-
-        } catch (Throwable e) {
-            e.printStackTrace();
-        }
-
-        return false;
-    }
-
-    // Search for the proper auth.properties entry corresponding
-    // to a particular incoming URL
-    // TODO: In the admin interface, often the operation is sent
-    // as one of the parameters to the message.
-    // There may be a way to extract this information at this level.
-    // The parameter name to scan for could be configured with the Realm.
-
-    public String getACLEntry(String requestURI) {
-
-        if (!hasAuthzProperties()) {
-            return null;
-        }
-
-        logDebug("Checking path: "+requestURI);
-        String aclEntryData = authzProperties.getProperty(requestURI);
-
-        if (aclEntryData != null) {
-            logDebug("Found exact match: "+aclEntryData);
-            return aclEntryData;
-        }
-
-        // Check for a partial match such as
-        // ex: /kra/pki/keyrequest/2
-        // TODO: Check into more sophisticated
-        // methods of doing this mapping.
-        // Perhaps Rest gives us this more
-        // sophisticated mapping ability.
-
-        Properties props = authzProperties;
-        Enumeration<?> e = props.propertyNames();
-
-        while (e.hasMoreElements()) {
-            String key = (String) e.nextElement();
-            if (requestURI.startsWith(key)) {
-                aclEntryData = props.getProperty(key);
-                logDebug("Found partial match ["+key+"]: "+aclEntryData);
-                break;
-            }
-        }
-
-        if (aclEntryData == null) {
-            logDebug("No match found");
-        }
-
-        return aclEntryData;
-
-    }
-
-    // Check to see if we have read in the auth properties file
-    public boolean hasAuthzProperties() {
-
-        if (authzProperties != null) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    // Load the custom mapping file auth.properties, which maps urls to acl resourceID and operation value
-    // example entry: /kra/pki/config/cert/transport = certServer.kra.pki.config.cert.transport,read
-    // TODO: Look into a more sophisticated method than this simple properties file if appropriate.
-    public synchronized void loadAuthzProperties(Context context) throws IOException {
-
-        if (authzProperties == null && context != null) {
-
-            InputStream inputStream = context.getServletContext().getResourceAsStream(PROP_AUTH_FILE_PATH);
-
-            if (inputStream == null) {
-                logDebug("Resource "+PROP_AUTH_FILE_PATH+" not found.");
-                throw new IOException("Resource "+PROP_AUTH_FILE_PATH+" not found.");
-            }
-
-            try {
-                logDebug("Loading authorization properties");
-
-                Properties properties = new Properties();
-                properties.load(inputStream);
-
-                authzProperties = properties;
-
-            } finally {
-                try {
-                    inputStream.close();
-                } catch (IOException e) {
-                    e.printStackTrace();
-                }
-            }
-        }
-    }
-
     /*
      * TODO: Figure out how to do real logging
      */
diff --git a/base/kra/shared/webapps/kra/WEB-INF/auth.properties b/base/kra/shared/webapps/kra/WEB-INF/auth.properties
index 0a529f060dc34dd9dde1b4a9570068ce8dd08286..567747f5b0d5aa504ef0184190d271d7ff2b64ab 100644
--- a/base/kra/shared/webapps/kra/WEB-INF/auth.properties
+++ b/base/kra/shared/webapps/kra/WEB-INF/auth.properties
@@ -1,12 +1,12 @@
 # Restful API auth/authz mapping info
 #
 # Format:
-# <Rest API URL> = <ACL Resource ID>,<ACL resource operation>
-# ex:      /kra/pki/key/retrieve = certServer.kra.pki.key.retrieve,execute
+# <ACL Mapping> = <ACL Resource ID>,<ACL Resource Operation>
+# ex:      admin.users = certServer.ca.users,read
 
-/kra/rest/account/login = certServer.kra.account,login
-/kra/rest/account/logout = certServer.kra.account,logout
-/kra/rest/admin/users = certServer.kra.users,execute
-/kra/rest/admin/groups = certServer.kra.groups,execute
-/kra/rest/agent/keys = certServer.kra.keys,execute
-/kra/rest/agent/keyrequests = certServer.kra.keyrequests,execute
+account.login = certServer.kra.account,login
+account.logout = certServer.kra.account,logout
+admin.users = certServer.kra.users,execute
+admin.groups = certServer.kra.groups,execute
+agent.keys = certServer.kra.keys,execute
+agent.keyrequests = certServer.kra.keyrequests,execute
diff --git a/base/kra/src/com/netscape/kra/KeyRecoveryAuthorityApplication.java b/base/kra/src/com/netscape/kra/KeyRecoveryAuthorityApplication.java
index 280ffe1dc1fbe93219e1269efc440a41d019d29d..0ed23f6971f6d0f7c1ec42301f7bb1a29b7e1a89 100644
--- a/base/kra/src/com/netscape/kra/KeyRecoveryAuthorityApplication.java
+++ b/base/kra/src/com/netscape/kra/KeyRecoveryAuthorityApplication.java
@@ -5,6 +5,7 @@ import java.util.Set;
 
 import javax.ws.rs.core.Application;
 
+import com.netscape.certsrv.acls.ACLInterceptor;
 import com.netscape.certsrv.base.PKIException;
 import com.netscape.cms.servlet.account.AccountService;
 import com.netscape.cms.servlet.admin.GroupMemberService;
@@ -45,6 +46,8 @@ public class KeyRecoveryAuthorityApplication extends Application {
         // exception mapper
         classes.add(PKIException.Mapper.class);
 
+        // ACL interceptor
+        singletons.add(new ACLInterceptor());
     }
 
     public Set<Class<?>> getClasses() {
diff --git a/base/ocsp/shared/webapps/ocsp/WEB-INF/auth.properties b/base/ocsp/shared/webapps/ocsp/WEB-INF/auth.properties
index 8eda09bc3c24cec750cc3ae271ba4388639215f4..cd2e14058f382429f0ca12813b275fee70ea7c09 100644
--- a/base/ocsp/shared/webapps/ocsp/WEB-INF/auth.properties
+++ b/base/ocsp/shared/webapps/ocsp/WEB-INF/auth.properties
@@ -1,10 +1,10 @@
 # Restful API auth/authz mapping info
 #
 # Format:
-# <Rest API URL> = <ACL Resource ID>,<ACL resource operation>
-# ex:      /kra/pki/key/retrieve = certServer.kra.pki.key.retrieve,execute
+# <ACL Mapping> = <ACL Resource ID>,<ACL Resource Operation>
+# ex:      admin.users = certServer.ca.users,read
 
-/ocsp/rest/account/login = certServer.ocsp.account,login
-/ocsp/rest/account/logout = certServer.ocsp.account,logout
-/ocsp/rest/admin/users = certServer.ocsp.users,execute
-/ocsp/rest/admin/groups = certServer.ocsp.groups,execute
+account.login = certServer.ocsp.account,login
+account.logout = certServer.ocsp.account,logout
+admin.users = certServer.ocsp.users,execute
+admin.groups = certServer.ocsp.groups,execute
diff --git a/base/ocsp/src/com/netscape/ocsp/OCSPApplication.java b/base/ocsp/src/com/netscape/ocsp/OCSPApplication.java
index e6816721cc017ebbfa90e11d662137299b2808ec..21b37f8010f2f25dec85d666581b8d5b34c0383d 100644
--- a/base/ocsp/src/com/netscape/ocsp/OCSPApplication.java
+++ b/base/ocsp/src/com/netscape/ocsp/OCSPApplication.java
@@ -5,6 +5,7 @@ import java.util.Set;
 
 import javax.ws.rs.core.Application;
 
+import com.netscape.certsrv.acls.ACLInterceptor;
 import com.netscape.certsrv.base.PKIException;
 import com.netscape.cms.servlet.account.AccountService;
 import com.netscape.cms.servlet.admin.GroupMemberService;
@@ -38,6 +39,9 @@ public class OCSPApplication extends Application {
 
         // exception mapper
         classes.add(PKIException.Mapper.class);
+
+        // ACL interceptor
+        singletons.add(new ACLInterceptor());
     }
 
     public Set<Class<?>> getClasses() {
diff --git a/base/tks/shared/webapps/tks/WEB-INF/auth.properties b/base/tks/shared/webapps/tks/WEB-INF/auth.properties
index 90897683e701cece4d25a294d4986ce768fc1aae..6de7f08e557a36742b603c87eda6a92ee6b9fa37 100644
--- a/base/tks/shared/webapps/tks/WEB-INF/auth.properties
+++ b/base/tks/shared/webapps/tks/WEB-INF/auth.properties
@@ -1,10 +1,10 @@
 # Restful API auth/authz mapping info
 #
 # Format:
-# <Rest API URL> = <ACL Resource ID>,<ACL resource operation>
-# ex:      /kra/pki/key/retrieve = certServer.kra.pki.key.retrieve,execute
+# <ACL Mapping> = <ACL Resource ID>,<ACL Resource Operation>
+# ex:      admin.users = certServer.ca.users,read
 
-/tks/rest/account/login = certServer.tks.account,login
-/tks/rest/account/logout = certServer.tks.account,logout
-/tks/rest/admin/users = certServer.tks.users,execute
-/tks/rest/admin/groups = certServer.tks.groups,execute
+account.login = certServer.tks.account,login
+account.logout = certServer.tks.account,logout
+admin.users = certServer.tks.users,execute
+admin.groups = certServer.tks.groups,execute
diff --git a/base/tks/src/com/netscape/tks/TKSApplication.java b/base/tks/src/com/netscape/tks/TKSApplication.java
index 5493bb4da0ffe6c6ba8159bcb1a3efb9da6b2079..229a64c95abe5b0dce25d94df89d6fc6c04904b8 100644
--- a/base/tks/src/com/netscape/tks/TKSApplication.java
+++ b/base/tks/src/com/netscape/tks/TKSApplication.java
@@ -5,6 +5,7 @@ import java.util.Set;
 
 import javax.ws.rs.core.Application;
 
+import com.netscape.certsrv.acls.ACLInterceptor;
 import com.netscape.certsrv.base.PKIException;
 import com.netscape.cms.servlet.account.AccountService;
 import com.netscape.cms.servlet.admin.GroupMemberService;
@@ -38,6 +39,9 @@ public class TKSApplication extends Application {
 
         // exception mapper
         classes.add(PKIException.Mapper.class);
+
+        // ACL interceptor
+        singletons.add(new ACLInterceptor());
     }
 
     public Set<Class<?>> getClasses() {
-- 
1.7.11.4

