From e538126dd9f84c6e8d59944d98690e06c3ca61b1 Mon Sep 17 00:00:00 2001
From: Ade Lee <alee@redhat.com>
Date: Sat, 16 Apr 2016 11:29:37 -0400
Subject: [PATCH 288/293] Added new authz methods to check realm

* Added method to check realm.  This method will look for
  an authz instance for a specified realm and invoke it to
  determine access.
* Added a basic group based authz plugin mostly for testing.
  This plugin simply checks if the requestor is in the correct
  group.  In practice, customers will probably want something more
  complex maybe subclassing BasicAclAuthz.

Part of Trac Ticket #2041
---
 .../certsrv/authorization/IAuthzSubsystem.java     |  19 +++
 .../cms/authorization/BasicGroupAuthz.java         | 186 +++++++++++++++++++++
 .../cmscore/authorization/AuthzSubsystem.java      |  40 ++++-
 3 files changed, 244 insertions(+), 1 deletion(-)
 create mode 100644 base/server/cms/src/com/netscape/cms/authorization/BasicGroupAuthz.java

diff --git a/base/common/src/com/netscape/certsrv/authorization/IAuthzSubsystem.java b/base/common/src/com/netscape/certsrv/authorization/IAuthzSubsystem.java
index b96499a77b4e54b419c2214d96b90e4b6f7c4ea0..156643897a07890eb7edd9555b3061a720322b71 100644
--- a/base/common/src/com/netscape/certsrv/authorization/IAuthzSubsystem.java
+++ b/base/common/src/com/netscape/certsrv/authorization/IAuthzSubsystem.java
@@ -58,6 +58,11 @@ public interface IAuthzSubsystem extends ISubsystem {
     public static final String PROP_INSTANCE = "instance";
 
     /**
+     * Constant for realm
+     */
+    public static final String PROP_REALM = "realm";
+
+    /**
      * authorize the user associated with the given authToken for a given
      * operation with the given authorization manager name
      *
@@ -76,6 +81,20 @@ public interface IAuthzSubsystem extends ISubsystem {
             String exp) throws EBaseException;
 
     /**
+     * Authorize the user against the specified realm.  Looks for authz manager
+     * associated with the plugin and authenticates if present.
+     *
+     * @param realm
+     * @param authToken
+     * @param owner TODO
+     * @param resource
+     * @param operation
+     * @throws EBaseException if any error occurs during authentication.
+     */
+    public void checkRealm(String realm, IAuthToken authToken,
+            String owner, String resource, String operation) throws EBaseException;
+
+    /**
      * Adds (registers) the given authorization manager.
      *
      * @param name The authorization manager name
diff --git a/base/server/cms/src/com/netscape/cms/authorization/BasicGroupAuthz.java b/base/server/cms/src/com/netscape/cms/authorization/BasicGroupAuthz.java
new file mode 100644
index 0000000000000000000000000000000000000000..1908e3c690a93af99a1cfde8f7d139e6e49ba1b1
--- /dev/null
+++ b/base/server/cms/src/com/netscape/cms/authorization/BasicGroupAuthz.java
@@ -0,0 +1,186 @@
+// --- 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) 2016 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+package com.netscape.cms.authorization;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Locale;
+import java.util.Vector;
+
+import com.netscape.certsrv.acls.ACL;
+import com.netscape.certsrv.acls.EACLsException;
+import com.netscape.certsrv.acls.IACL;
+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.EAuthzInternalError;
+import com.netscape.certsrv.authorization.IAuthzManager;
+import com.netscape.certsrv.base.EBaseException;
+import com.netscape.certsrv.base.IConfigStore;
+import com.netscape.certsrv.base.IExtendedPluginInfo;
+import com.netscape.certsrv.evaluators.IAccessEvaluator;
+import com.netscape.certsrv.usrgrp.IGroup;
+import com.netscape.certsrv.usrgrp.IUGSubsystem;
+import com.netscape.cmsutil.util.Utils;
+
+public class BasicGroupAuthz implements IAuthzManager, IExtendedPluginInfo {
+
+    private static final String GROUP = "group";
+
+    /* name of this authorization manager instance */
+    private String name = null;
+
+    /* name of the authorization manager plugin */
+    private String implName = null;
+
+    /* configuration store */
+    private IConfigStore config;
+
+    /* group that is allowed to access resources */
+    private String groupName = null;
+
+    /* Vector of extendedPluginInfo strings */
+    protected static Vector<String> mExtendedPluginInfo = null;
+
+    protected static String[] mConfigParams = null;
+
+    static {
+        mExtendedPluginInfo = new Vector<String>();
+        mExtendedPluginInfo.add("group;string,required;" +
+                "Group to permit access");
+    }
+
+    public BasicGroupAuthz() {
+        mConfigParams = new String[] {"group"};
+    }
+
+    @Override
+    public String[] getExtendedPluginInfo(Locale locale) {
+        String[] s = Utils.getStringArrayFromVector(mExtendedPluginInfo);
+        return s;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public String getImplName() {
+        return implName;
+    }
+
+    @Override
+    public void accessInit(String accessInfo) throws EBaseException {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public AuthzToken authorize(IAuthToken authToken, String resource, String operation)
+            throws EAuthzInternalError, EAuthzAccessDenied {
+        String user = authToken.getInString(IAuthToken.USER_ID);
+        if (user == null) {
+            throw new EAuthzAccessDenied("No userid provided");
+        }
+
+        IUGSubsystem ug = (IUGSubsystem) CMS.getSubsystem(CMS.SUBSYSTEM_UG);
+        IGroup group = ug.getGroupFromName(groupName);
+        if (!group.isMember(user)) {
+            throw new EAuthzAccessDenied("Access denied");
+        }
+
+        CMS.debug("BasicGroupAuthz: authorization passed");
+
+        // compose AuthzToken
+        AuthzToken authzToken = new AuthzToken(this);
+        authzToken.set(AuthzToken.TOKEN_AUTHZ_RESOURCE, resource);
+        authzToken.set(AuthzToken.TOKEN_AUTHZ_OPERATION, operation);
+        authzToken.set(AuthzToken.TOKEN_AUTHZ_STATUS, AuthzToken.AUTHZ_STATUS_SUCCESS);
+
+        return authzToken;
+    }
+
+    @Override
+    public AuthzToken authorize(IAuthToken authToken, String expression)
+            throws EAuthzInternalError, EAuthzAccessDenied {
+        return authorize(authToken, null, null);
+    }
+
+    @Override
+    public void init(String name, String implName, IConfigStore config) throws EBaseException {
+        this.name = name;
+        this.implName = implName;
+        this.config = config;
+
+        groupName = config.getString(GROUP);
+    }
+
+    @Override
+    public void shutdown() {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    public String[] getConfigParams() throws EBaseException {
+        return mConfigParams;
+    }
+
+    @Override
+    public IConfigStore getConfigStore() {
+        return config;
+    }
+
+    @Override
+    public Enumeration<ACL> getACLs() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public IACL getACL(String target) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public void updateACLs(String id, String rights, String strACLs, String desc) throws EACLsException {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public Enumeration<IAccessEvaluator> aclEvaluatorElements() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public void registerEvaluator(String type, IAccessEvaluator evaluator) {
+        // TODO Auto-generated method stub
+
+    }
+
+    @Override
+    public Hashtable<String, IAccessEvaluator> getAccessEvaluators() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+}
diff --git a/base/server/cmscore/src/com/netscape/cmscore/authorization/AuthzSubsystem.java b/base/server/cmscore/src/com/netscape/cmscore/authorization/AuthzSubsystem.java
index a6019730a954418ffb5fa37b96dc1a5a77cbcf85..8b126d2dac047b450e7a90fcf27263628b169c90 100644
--- a/base/server/cmscore/src/com/netscape/cmscore/authorization/AuthzSubsystem.java
+++ b/base/server/cmscore/src/com/netscape/cmscore/authorization/AuthzSubsystem.java
@@ -21,11 +21,14 @@ import java.util.Enumeration;
 import java.util.Hashtable;
 import java.util.Vector;
 
+import org.apache.commons.codec.binary.StringUtils;
+
 import com.netscape.certsrv.apps.CMS;
 import com.netscape.certsrv.authentication.IAuthToken;
 import com.netscape.certsrv.authorization.AuthzManagerProxy;
 import com.netscape.certsrv.authorization.AuthzMgrPlugin;
 import com.netscape.certsrv.authorization.AuthzToken;
+import com.netscape.certsrv.authorization.EAuthzAccessDenied;
 import com.netscape.certsrv.authorization.EAuthzException;
 import com.netscape.certsrv.authorization.EAuthzMgrNotFound;
 import com.netscape.certsrv.authorization.EAuthzMgrPluginNotFound;
@@ -156,6 +159,7 @@ public class AuthzSubsystem implements IAuthzSubsystem {
                     // it is mis-configurated. This give
                     // administrator another chance to
                     // fix the problem via console
+                    CMS.debug(e);
                 } catch (Throwable e) {
                     log(ILogger.LL_FAILURE,
                             CMS.getLogMessage("CMSCORE_AUTHZ_PLUGIN_INIT_FAILED", insName, e.toString()));
@@ -163,6 +167,7 @@ public class AuthzSubsystem implements IAuthzSubsystem {
                     // it is mis-configurated. This give
                     // administrator another chance to
                     // fix the problem via console
+                    CMS.debug(e);
                 }
                 // add manager instance to list.
                 mAuthzMgrInsts.put(insName, new
@@ -212,7 +217,7 @@ public class AuthzSubsystem implements IAuthzSubsystem {
      * Authorization to the named authorization manager instance
      *
      * @param authzMgrName The authorization manager name
-     * @param authToken the authenticaton token associated with a user
+     * @param authToken the authentication token associated with a user
      * @param resource the resource protected by the authorization system
      * @param operation the operation for resource protected by the authoriz
      *            n system
@@ -465,4 +470,37 @@ public class AuthzSubsystem implements IAuthzSubsystem {
                 level, msg);
     }
 
+    @Override
+    public void checkRealm(String realm, IAuthToken authToken, String owner, String resource, String operation)
+            throws EBaseException {
+        // if no realm entry, SUCCESS by default
+        if (realm == null) return;
+
+        // if record owner == requester, SUCCESS
+        if ((owner != null) && owner.equals(authToken.getInString(IAuthToken.USER_ID))) return;
+
+        String mgrName = getAuthzManagerByRealm(realm);
+        // if no authz manager for this realm, SUCCESS by default
+        if (mgrName == null) return;
+
+        AuthzToken authzToken = authorize(mgrName, authToken, resource, operation);
+        if (authzToken == null) {
+            throw new EAuthzAccessDenied("Not authorized by ACL realm");
+        }
+    }
+
+    public String getAuthzManagerByRealm(String realm) throws EBaseException {
+        for (AuthzManagerProxy proxy : mAuthzMgrInsts.values()) {
+            IAuthzManager mgr = proxy.getAuthzManager();
+            if (mgr != null) {
+                IConfigStore cfg = mgr.getConfigStore();
+                String mgrRealm = cfg.getString(PROP_REALM, null);
+                if (StringUtils.equals(mgrRealm, realm)) {
+                    return mgr.getName();
+                }
+            }
+        }
+        return null;
+    }
+
 }
-- 
2.4.3

