Asignación de roles externa

Edge para nube privada v4.18.01

La asignación de roles externos te permite asignar tus propios grupos o roles a los roles y grupos de control de acceso basado en roles (RBAC) creados en Apigee Edge. Esta función solo está disponible con Edge Private Cloud.

Novedades

Se dio de baja el servicio de asignación de roles externos para las versiones de Edge para la nube privada anteriores a la 4.18.01. La versión 4.18.01 de la asignación de roles externos es una versión actualizada con correcciones de errores y funciones nuevas:

  • Se solucionó el problema por el que recibías respuestas de autenticación 403 prohibidas cuando te autenticabas con usuarios que deberían tener acceso.
  • El encabezado X-Apigee-Current-User ahora se admite en la asignación de roles externos. Los usuarios con el acceso adecuado (administrador del sistema) ahora pueden ver los roles asignados a otro usuario.

Requisitos previos

  • Debes ser un administrador del sistema de Apigee nube privada con credenciales de administrador del sistema global para realizar esta configuración.
  • Debes conocer el directorio raíz de tu instalación de la nube privada de Apigee Edge. El directorio raíz predeterminado es /opt.

Ejemplo de configuración paso a paso

Consulta este artículo en los foros de la comunidad de Apigee para ver un ejemplo paso a paso de cómo configurar la asignación de roles externos.

Configuración predeterminada

La asignación de roles externos está inhabilitada de forma predeterminada.

Habilita la asignación de roles externos

  1. Antes de completar la siguiente configuración, debes crear una clase de Java que implemente la interfaz ExternalRoleMapperServiceV2 y que incluya tu implementación en la ruta de clase del servidor de administración:

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

    Para obtener detalles sobre esta implementación, consulta la sección Acerca de la implementación de muestra de ExternalRoleMapperImpl más adelante en este documento.
  2. Accede a tu servidor de administración de Apigee Edge y, luego, detén el proceso del servidor de administración:
    > /opt/apigee/apigee-service/bin/apigee-service edge-management-server stop
  3. Abre /opt/apigee/customer/application/management-server.properties en un editor de texto. Si este archivo no existe, créalo.
  4. Edita el archivo de propiedades para establecer la siguiente configuración:
    # El almacén de usuarios que se usará para la autenticación.
    # Usa "externalized.authentication" para el almacén de usuarios de LDAP.
    # Ten en cuenta que, para la autorización, seguimos usando LDAP.
    # Consulta Habilita la autenticación externa para obtener más información sobre cómo habilitar la autenticación externa.
    conf_security_authentication.user.store=externalized.authentication

    #Habilita el asignador de roles de autorizaciones externas.
    conf_security_externalized.authentication.role.mapper.enabled=true conf_security_externalized.authentication.role.mapper.implementation.class=
    com.customer.authorization.impl.ExternalRoleMapperImpl

    Importante:
    La clase de implementación y el nombre del paquete a los que se hace referencia en la configuración anterior (ExternalRoleMapperImpl) son solo ejemplos: es una clase que debes implementar y que puedes nombrar la clase y el paquete como desees. Para obtener detalles sobre cómo implementar esta clase, consulta la clase Acerca de la implementación de muestra de ExternalRoleMapperImpl que aparece a continuación. Esta es una clase que debes implementar para reflejar tus propios grupos.
  5. Guarda el archivo management-server.properties.
  6. Asegúrate de que management-server.properties sea propiedad del usuario de Apigee:?
    > chown apigee:apigee /opt/apigee/customer/application/management-server.properties
  7. Inicia el servidor de administración:
    > /opt/apigee/apigee-service/bin/apigee-service edge-management-server start

Inhabilita la autorización externa

Para inhabilitar la autorización externa, sigue estos pasos:

  1. Abre /opt/apigee/customer/application/management-server.properties en un editor de texto. Si el archivo no existe, créalo.
  2. Cambia el almacén de usuarios de autenticación a ldap:
    conf_security_authentication.user.store=ldap
  3. Establece esta propiedad como falsa:
    conf_security_externalized.authentication.role.mapper.enabled=false
  4. Reinicia el servidor de administración:
    > /opt/apigee/apigee-service/bin/apigee-service edge-management-server start

Acerca de la implementación de muestra de ExternalRoleMapperImpl

En el archivo de configuración security.properties que se describió anteriormente en Habilita la asignación de roles externos, observa esta línea:

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

Esta clase implementa la interfaz ExternalRoleMapperServiceV2 y es obligatoria. Debes crear tu propia implementación de esta clase que refleje tus grupos respectivos. Cuando termines, coloca la clase compilada en un JAR y colócalo en la ruta de clase del servidor de administración en:

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

Puedes asignar el nombre que desees a la clase y al paquete, siempre que implemente ExternalRoleMapperServiceV2, sea accesible en tu ruta de clase y se haga referencia a él correctamente en el archivo de configuración management-server.properties.

A continuación, ofrecemos una implementación de muestra bien comentada de una clase 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();
   }

}