نگاشت نقش خارجی

Edge for Private Cloud نسخه ۴.۱۸.۰۱

«نگاشت نقش خارجی» به شما امکان می‌دهد گروه‌ها یا نقش‌های خودتان را به نقش‌ها و گروه‌های کنترل دسترسی نقش‌مبنا (RBAC) ایجادشده در Apigee Edge نگاشت کنید. این ویژگی فقط با Edge Private Cloud دردسترس است.

ویژگی‌های جدید

سرویس «نگاشت نقش خارجی» برای نسخه‌های Edge for Private Cloud قبل‌از ۴.۱۸.۰۱ منسوخ شده است. نسخه ۴.۱۸.۰۱ از «نگاشت نقش خارجی» نسخه به‌روزشده‌ای است که اشکالات آن برطرف شده است و ویژگی‌های جدیدی به آن اضافه شده است:

  • مشکلی را که باعث می‌شد هنگام اصالت‌سنجی با کاربرانی که باید دسترسی داشته باشند، پاسخ‌های ممنوع 403 اصالت‌سنجی دریافت کنید برطرف کردیم.
  • اکنون سرصفحه X-Apigee-Current-User در «نگاشت نقش خارجی» پشتیبانی می‌شود. کاربران با دسترسی مناسب (سرپرست سیستم) اکنون می‌توانند نقش‌های اختصاص‌داده‌شده به کاربر دیگر را مشاهده کنند.

پیش‌نیازها

  • برای انجام این پیکربندی، باید سرپرست سیستم Apigee Private Cloud با اعتبارنامه سرپرست سیستم جهانی باشید.
  • باید دایرکتوری ریشه نصب Apigee Edge Private Cloud را بدانید. دایرکتوری ریشه پیش‌فرض /opt است.

نمونه راه‌اندازی گام‌به‌گام

برای مشاهده نمونه گام‌به‌گام راه‌اندازی نگاشت نقش خارجی، این مقاله را در «تالارهای گفتمان انجمن Apigee» ببینید.

پیکربندی پیش‌فرض

نگاشت نقش خارجی به‌طور پیش‌فرض غیرفعال است.

درحال فعال کردن «نگاشت نقش خارجی»

  1. قبل‌از اینکه بتوانید پیکربندی زیر را تکمیل کنید، باید کلاس Java ایجاد کنید که واسط ExternalRoleMapperServiceV2 را پیاده‌سازی کند و پیاده‌سازی‌تان را در مسیر کلاس Management Server اضافه کنید:

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

    برای جزئیات بیشتر درباره این پیاده‌سازی، بخش درباره پیاده‌سازی نمونه ExternalRoleMapperImpl را در ادامه این سند ببینید.
  2. به سرور مدیریت Apigee Edge وارد شوید و سپس فرایند سرور مدیریت را متوقف کنید:
    > /opt/apigee/apigee-service/bin/apigee-service edge-management-server stop
  3. /opt/apigee/customer/application/management-server.properties را در ویرایشگر نوشتار باز کنید. اگر این فایل وجود ندارد، آن را ایجاد کنید.
  4. فایل ویژگی‌ها را ویرایش کنید تا تنظیمات زیر را انجام دهید:
    # فروشگاه کاربر که برای اصالت‌سنجی استفاده می‌شود.
    # Use "externalized.authentication" for LDAP user store.
    # Note that for authorization, we continue to use LDAP.
    # برای کسب اطلاعات بیشتر درباره فعال کردن اصالت‌سنجی خارجی، فعال کردن اصالت‌سنجی خارجی را ببینید.
    conf_security_authentication.user.store=externalized.authentication

    #Enable the external authorizations role mapper.
    conf_security_externalized.authentication.role.mapper.enabled=true conf_security_externalized.authentication.role.mapper.implementation.class=
    com.customer.authorization.impl.ExternalRoleMapperImpl

    مهم:
    کلاس پیاده‌سازی و نام بسته ارجاع‌شده در پیکربندی بالا (ExternalRoleMapperImpl) فقط نمونه هستند -- این کلاسی است که باید پیاده‌سازی کنید و می‌توانید کلاس و بسته را هرطور که می‌خواهید نام‌گذاری کنید. برای جزئیات درباره پیاده‌سازی این کلاس، به کلاس درباره پیاده‌سازی نمونه 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_authentication.user.store=ldap
  3. این ویژگی را روی false تنظیم کنید:
    conf_security_externalized.authentication.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();
   }

}