ربط الأدوار الخارجية

الإصدار 4.18.01 من Edge الخاص بخدمة Private Cloud

تتيح لك ميزة "ربط الأدوار الخارجية" ربط مجموعاتك أو أدوارك بأدوار ومجموعات التحكّم في الوصول المستندة إلى الدور (RBAC) التي تم إنشاؤها في Apigee Edge. لا تتوفّر هذه الميزة إلا مع Edge Private Cloud.

الميزات الجديدة

تم نهائيًا إيقاف خدمة "تحديد الأدوار الخارجية" في إصدارات Edge for Private Cloud التي تسبق الإصدار 4.18.01. الإصدار 4.18.01 من ميزة "تحديد الأدوار الخارجية" هو نسخة معدّلة تم إصلاح أخطاء فيها، وتمت إضافة ميزات جديدة:

  • تم إصلاح المشكلة المتمثلة في تلقّي استجابات 403 محظورة للمصادقة عند المصادقة مع مستخدمين ينبغي أن يكون لديهم حق الوصول.
  • يتوفّر عنوان X-Apigee-Current-User الآن في ميزة "ربط الأدوار الخارجية". ويمكن الآن للمستخدمين الذين يملكون إذن الوصول المناسب (مسؤول إدارة النظم) عرض الأدوار التي تم إسنادها إلى مستخدم آخر.

المتطلبات الأساسية

  • يجب أن تكون مشرفًا على نظام Apigee Private Cloud وتمتلك بيانات اعتماد مشرف النظام العام لتنفيذ هذه الإعدادات.
  • عليك معرفة الدليل الجذري لتثبيت Apigee Edge Private Cloud. الدليل الجذر التلقائي هو /opt.

مثال على الإعداد خطوة بخطوة

يمكنك الاطّلاع على هذه المقالة حول منتديات Apigee للحصول على مثال مفصّل حول إعداد عملية ربط الأدوار الخارجية.

الضبط التلقائي

يكون تعيين الأدوار الخارجية غير مفعَّل تلقائيًا.

تفعيل تعيين الأدوار الخارجية

  1. قبل أن تتمكن من إكمال عملية الإعداد التالية، يجب إنشاء فئة Java تنفِّذ واجهة ExternalRoleMapperServiceV2 وتتضمّن عملية التنفيذ في مسار فئة خادم الإدارة:

    /opt/apigee/edge-management-server/lib/thirdparty/

    لمعرفة تفاصيل عن عملية التنفيذ هذه، يُرجى الاطّلاع على القسم لمحة عن تنفيذ السياسة ExternalRoleMapperImpl لاحقًا.
  2. سجِّل الدخول إلى خادم إدارة Apigee Edge ثم أوقِف عملية خادم الإدارة:
    > /opt/apigee/apigee-service/bin/apigee-service Edge-management-server تستخدمه
  3. افتح /opt/apigee/customer/application/management-server.properties في محرِّر نصوص. إذا لم يكن هذا الملف موجودًا، فأنشئه.
  4. عدِّل ملف الخصائص لضبط الإعدادات التالية:
    # ملف تخزين المستخدم المطلوب استخدامه للمصادقة.
    # استخدِم "externalized.authentction" في متجر مستخدمي LDAP.
    # يُرجى العلم أنّنا سنواصل استخدام LDAP لأغراض التفويض.
    # يمكنك الاطّلاع على تفعيل المصادقة الخارجية لمعرفة مزيد من المعلومات حول تفعيل المصادقة الخارجية.
    conf_security_authentction.user.store=externalized.authentication

    #تفعيل مصمم خرائط دور عمليات التفويض الخارجية.
    conf_security_externalized.authentracy.role.mapper.enabled=true conf_security_externalized.authentification.role.mapper.usage.class=
    com.customer.authorization.impl.ExternalRoleMapperImpl

    ملاحظة مهمّة:
    يجب أن تكون فئة التنفيذ واسم الحزمة المُشار إليها في الإعدادات أعلاه، أيّ اسم فئة أو حزمة مُشار إليها في الإعدادات أعلاه، مثل أيّ فئة تنفيذ أو اسم حزمة [ExternalRoleMapper] يمكنك استخدامها فقط. للاطّلاع على تفاصيل حول تنفيذ هذه الفئة، يُرجى مراجعة لمحة عن فئة تنفيذ نموذج ExternalRoleMapperImpl أدناه. هذا فئة عليك تنفيذها لتعكس مجموعاتك الخاصة.
  5. احفظ الملف management-server.properties.
  6. تأكَّد من أنّ management-server.properties يملكه مستخدم apigee:؟
    > chown apigee:apigee /opt/apigee/customer/application/management-server.properties
  7. ابدأ تشغيل خادم الإدارة:
    > /opt/apigee/apigee-service/bin/apigee-service Edge-management-server start

إيقاف التفويض الخارجي

لإيقاف التفويض الخارجي:

  1. افتح /opt/apigee/customer/application/management-server.properties في محرِّر نصوص. إذا لم يكن الملف موجودًا، فأنشئه.
  2. غيِّر متجر مستخدم المصادقة إلى ldap:
    conf_security_authentction.user.store=ldap
  3. اضبط هذه السمة على "خطأ":
    conf_security_externalized.authentification.role.mapper.enabled=false
  4. أعِد تشغيل خادم الإدارة:
    > /opt/apigee/apigee-service/bin/apigee-service Edge-management-server start

لمحة عن نموذج تنفيذ ExternalRoleMapperImpl

في ملف إعداد Security.properties المُوضَّح سابقًا في تفعيل ربط الأدوار الخارجية، يُرجى ملاحظة السطر التالي:

externalized.authentication.role.mapper.implementation.class=com.customer.authorization.impl.ExternalRoleMapperImpl

تنفِّذ هذه الفئة واجهة ExternalRoleMapperServiceV2، وهي مطلوبة. يجب إنشاء عملية التنفيذ الخاصة بك لهذا الصف والتي تعكس المجموعات المعنيّة. عند الانتهاء، ضَع الفئة المجمّعة في JAR وضع JAR في مسار فئة خادم الإدارة في:

/opt/apigee/edge-management-server/lib/thirdparty/

يمكنك تسمية الفئة والحزمة بأي اسم تريده ما دام يستخدم ExternalRoleMapperServiceV2 ويمكن الوصول إليها في مسار الفئة وتتم الإشارة إليه بشكل صحيح في ملف الإعداد Management-server.properties.

نعرض في ما يلي نموذجًا تمت مراجعته جيدًا لفئة ExternalRoleMapperImpl.

package com.customer.authorization.impl;

import com.apigee.authentication.*;
import com.apigee.authorization.namespace.OrganizationNamespace;
import com.apigee.authorization.namespace.SystemNamespace;
import java.util.Collection;
import java.util.HashSet;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;

/** *
* Sample Implementation constructed with dummy roles with expected namespaces.
*/

public class ExternalRoleMapperImpl
       implements ExternalRoleMapperServiceV2 {

   InitialDirContext dirContext = null;

   @Override
   public void start(ConfigBean arg0) throws ConnectionException {

       try {
           // Customer Specific Implementation will override the
           // ImplementDirContextCreationLogicForSysAdmin method implementation.
           // Create InitialDirContext based on the system admin user credentials.
           dirContext = ImplementDirContextCreationLogicForSysAdmin();
       } catch (NamingException e) {
           // TODO Auto-generated catch block
           throw new ConnectionException(e);
       }
   }

   @Override
   public void stop() throws Exception {
   }

   /**
    * This method should be replaced with customer's implementation
    * For given roleName under expectedNamespace, return all users that belongs to this role
    * @param roleName
    * @param expectedNamespace
    * @return All users that belongs to this role. For each user, please return the username/email that is stored in Apigee LDAP
    * @throws ExternalRoleMappingException
    */
   @Override
   public Collection<String> getUsersForRole(String roleName, NameSpace expectedNamespace) throws ExternalRoleMappingException {
       Collection<String> users = new HashSet<>();
       if (expectedNamespace instanceof SystemNamespace) {
           // If requesting all users with sysadmin role
           if (roleName.equalsIgnoreCase("sysadmin")) {
               // Add sysadmin's email to results
               users.add("sysadmin@wacapps.net");
           }
       } else {
           String orgName = ((OrganizationNamespace) expectedNamespace).getOrganization();
           // If requesting all users of engRole in Apigee LDAP
           if (roleName.equalsIgnoreCase("engRole")) {
               // Get all users in corresponding groups in customer's LDAP. In this case looking for 'engGroup';
               SearchControls controls = new SearchControls();
               controls.setSearchScope(1);
               try {
                   NamingEnumeration<SearchResult> res = dirContext.search("ou=groups,dc=corp,dc=wacapps,dc=net",
                           "cn=engGroup", new Object[]{"",""}, controls);
                   while (res.hasMoreElements()) {
                       SearchResult sr = res.nextElement();
                       // Add all users into return
                       users.addAll(sr.getAttributes().get("users").getAll());
                   }
               } catch (NamingException e) {
                   // Customer needs to handle the exception here
               }
           }
       }
       return users;
   }

   /**
    *
    * This method would be implemented by the customer and would be invoked
    * while including using X-Apigee-Current-User header in request.
    *
    * X-Apigee-Current-User allows the customer to login as another user
    *
    * Below is the basic example.
    *
    * If User has sysadmin role then it's expected to set SystemNameSpace
    * along with the expected NameSpace. Otherwise role's expectedNameSpace
    * to be set for the NameSpacedRole.
    *
    * Collection<NameSpacedRole> results = new HashSet<NameSpacedRole>();
    *
    * NameSpacedRole sysNameSpace = new NameSpacedRole("sysadmin",
    * SystemNamespace.get());
    *
    * String orgName =
    * ((OrganizationNamespace) expectedNameSpace).getOrganization();
    *
    * NameSpacedRole orgNameSpace = new NameSpacedRole ("orgadmin",
    * expectedNameSpace);
    *
    * results.add(sysNameSpace);
    *
    * results.add(orgNameSpace);
    *
    *
    * @param username UserA's username
    * @param password UserA's password
    * @param requestedUsername UserB's username. Allow UserA to request UserB's userroles with
    *                          UserA's credentials when requesting UserB as X-Apigee-Current-User
    * @param expectedNamespace
    * @return
    * @throws ExternalRoleMappingException
    */
   @Override
   public Collection<NameSpacedRole> getUserRoles(String username, String password, String requestedUsername, NameSpace expectedNamespace) throws ExternalRoleMappingException {
       /************************************************************/
       /******************** Authenticate UserA ********************/
       /************************************************************/

       // Customer Specific Implementation will override the
       // ImplementDnameLookupLogic method implementation.

       // obtain dnName for given username.
       String dnName = ImplementDnNameLookupLogic(username);
       // Obtain dnName for given requestedUsername.
       String requestedDnName = ImplementDnNameLookupLogic(requestedUsername);

       if (dnName == null || requestedDnName == null) {
           System.out.println("Error ");
       }

       DirContext dirContext = null;
       try {

           // Customer Specific Implementation will override the
           // ImplementDirectoryContextCreationLogic method implementation

           // Create a directory context with dnName or requestedDnName and password
           dirContext = ImplementDirectoryContextCreationLogic();

           /************************************************/
           /*** Map internal groups to apigee-edge roles ***/
           /************************************************/
           return apigeeEdgeRoleMapper(dirContext, requestedDnName, expectedNamespace);

       } catch (Exception ex) {
           ex.printStackTrace();
           System.out.println("Error in authenticating User: {}" + new Object[] { username });

       } finally {
           // Customer implementation to close
           // ActiveDirectory/LDAP context.
       }

       return null;

   }

   /**
    *
    * This method would be implemented by the customer and would be invoked
    * wihle using username and password for authentication and without the
    * X-Apigee-Current-User header
    *
    * The customer can reuse implementations in
    *      getUserRoles(String username, String password, String requestedUsername, NameSpace expectedNamespace)
    * by
    *      return getUserRoles(username, password, username, expectedNamespace)
    * in implementations.
    *
    * or the customer can provide new implementations as shown below.
    */

   @Override
   public Collection<NameSpacedRole> getUserRoles(String username, String password, NameSpace expectedNamespace) throws ExternalRoleMappingException {
       /*************************************************************/
       /****************** Authenticate Given User ******************/
       /*************************************************************/

       // Customer Specific Implementation will override the
       // ImplementDnameLookupLogic implementation.

       // Obtain dnName for given username or email address.
       String dnName = ImplementDnNameLookupLogic(username);

       if (dnName == null) {
           System.out.println("Error ");
       }

       DirContext dirContext = null;
       try {
           // Create a directory context with username or dnName and password
           dirContext = ImplementDirectoryContextCreationLogic();

           /************************************************/
           /*** Map internal groups to apigee-edge roles ***/
           /************************************************/
           return apigeeEdgeRoleMapper(dirContext, dnName, expectedNamespace);

       } catch (Exception ex) {
           ex.printStackTrace();
           System.out.println("Error in authenticating User: {}" + new Object[] { username });

       } finally {
           // Customer implementation to close
           // ActiveDirectory/LDAP context.
       }

       return null;
   }

   /**
    *
    * This method would be implemented by the customer and would be invoked
    * while using security token or access token as authentication credentials.
    *
    */
   @Override
   public Collection<NameSpacedRole> getUserRoles(String username, NameSpace expectedNamespace) throws ExternalRoleMappingException {

       /*************************************************************/
       /****************** Authenticate Given User ******************/
       /*************************************************************/

       // Customer Specific Implementation will override the
       // ImplementDnameLookupLogic implementation.

       // Obtain dnName for given username or email address.
       String dnName = ImplementDnNameLookupLogic(username);

       if (dnName == null) {
           System.out.println("Error ");
       }

       DirContext dirContext = null;
       try {
           // Create a directory context with username or dnName and password
           dirContext = ImplementDirectoryContextCreationLogic();

           /************************************************/
           /*** Map internal groups to apigee-edge roles ***/
           /************************************************/
           return apigeeEdgeRoleMapper(dirContext, dnName, expectedNamespace);

       } catch (Exception ex) {
           ex.printStackTrace();
           System.out.println("Error in authenticating User: {}" + new Object[] { username });

       } finally {
           // Customer implementation to close
           // ActiveDirectory/LDAP context.
       }

       return null;
   }

   /**
    *  This method should be replaced with Customer Specific Implementations
    *
    *  Provided as a sample Implementation of mapping user groups to apigee-edge roles
    */
   private Collection<NameSpacedRole> apigeeEdgeRoleMapper(DirContext dirContext, String dnName, NameSpace expectedNamespace) throws Exception {

       Collection<NameSpacedRole> results = new HashSet<NameSpacedRole>();

       /****************************************************/
       /************ Fetch internal groups *****************/
       /****************************************************/

       String groupDN = "OU=Groups,DC=corp,DC=wacapps,DC=net";
       String userFilter = "(user=userDnName)";
       SearchControls controls = new SearchControls();
       controls.setSearchScope(SearchControls.ONELEVEL_SCOPE);

       // Looking for all groups the user belongs to in customer's LDAP
       NamingEnumeration<SearchResult> groups = dirContext.search(groupDN,userFilter.replace("userDnName", dnName), new Object[] { "", "" }, controls);

       if (groups.hasMoreElements()) {
           while (groups.hasMoreElements()) {
               SearchResult searchResult = groups.nextElement();
               Attributes attributes = searchResult.getAttributes();
               String groupName = attributes.get("name").get().toString();

               /************************************************/
               /*** Map internal groups to apigee-edge roles ***/
               /************************************************/

               if (groupName.equals("BusDev")) {
                   results.add(new NameSpacedRole("businessAdmin",SystemNamespace.get()));

               } else if (groupName.equals("Engineering")) {
                   if (expectedNamespace instanceof OrganizationNamespace) {
                       String orgName = ((OrganizationNamespace) expectedNamespace).getOrganization();
                       results.add(new NameSpacedRole("orgadmin", new OrganizationNamespace(orgName)));
                   }

               } else if (groupName.equals("Marketing")) {
                   results.add(new NameSpacedRole("marketAdmin",SystemNamespace.get()));

               } else {
                   results.add(new NameSpacedRole("readOnly",SystemNamespace.get()));
               }
           }

       } else {
           // In case of no group found or exception found we throw empty roles.
           System.out.println(" !!!!! NO  GROUPS FOUND !!!!!");
       }
       return results;
   }

   /**
    * The customer need to replace with own implementations for getting dnName for given user
    */
   private String ImplementDnNameLookupLogic(String username) {
       // Connect to the customer's own LDAP to fetch user dnName
       return customerLDAP.getDnName(username);
   }

   /**
    * The customer need to replace with own implementations for creating DirContext
    */
   private DirContext ImplementDirectoryContextCreationLogic() {
       // Connect to the customer's own LDAP to create DirContext for given user
       return customerLDAP.createLdapContextUsingCredentials();
   }

}