Mappatura dei ruoli esterna

Edge per Private Cloud v4.18.01

La mappatura dei ruoli esterni consente di mappare gruppi o ruoli personalizzati a ruoli di controllo dell'accesso basato sui ruoli (RBAC) e gruppi creati su Apigee Edge. Questa funzionalità è disponibile solo con Edge Private Cloud.

Novità

Il servizio di mappatura dei ruoli esterno per le release Edge per Cloud privato precedenti alla versione 4.18.01 è stato deprecato. La release 4.18.01 di External Role Mapping è una versione aggiornata con bug corretti e nuove funzionalità aggiunte:

  • Risolto il problema a causa del quale ricevevi risposte di tipo vietato per l'autenticazione 403 durante l'autenticazione con utenti che dovrebbero avere accesso.
  • L'intestazione X-Apigee-Current-User è ora supportata nella mappatura dei ruoli esterno. Gli utenti con accesso corretto (amministratore di sistema) ora possono visualizzare i ruoli assegnati a un altro utente.

Prerequisiti

  • Per eseguire questa configurazione, devi essere un amministratore di sistema del cloud privato Apigee con credenziali di amministratore di sistema globali.
  • Devi conoscere la directory radice dell'installazione del cloud privato Apigee Edge. La directory principale predefinita è /opt.

Esempio di configurazione passo passo

Consulta questo articolo sui forum della community di Apigee per un esempio dettagliato della configurazione della mappatura dei ruoli esterni.

Configurazione predefinita

La mappatura dei ruoli esterni è disabilitata per impostazione predefinita.

Abilitazione della mappatura dei ruoli esterni

  1. Prima di poter completare la seguente configurazione, devi creare una classe Java che implementi l'interfaccia ExternalRoleMapperServiceV2 e includere la tua implementazione nel classpath del server di gestione:

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

    Per maggiori dettagli su questa implementazione, consulta la sezione Informazioni sull'implementazione di esempio di ExternalRoleMapperImpl più avanti in questo documento.
  2. Accedi al server di gestione Apigee Edge e poi interrompi il processo del server di gestione:
    > /opt/apigee/apigee-service/bin/apigee-service edge-management-server stop
  3. Apri /opt/apigee/customer/application/management-server.properties in un editor di testo. Se il file non esiste, crealo.
  4. Modifica il file delle proprietà per apportare le seguenti impostazioni:
    # L'archivio utenti da utilizzare per l'autenticazione.
    # Utilizza "externalized.authentication" per l'archivio utenti LDAP.
    # Tieni presente che, per l'autorizzazione, continueremo a utilizzare LDAP.
    # Vedi Abilitazione dell'autenticazione esterna per saperne di più sull'abilitazione dell'autenticazione esterna.
    conf_security_authentication.user.store=externalized.authentication

    #Abilita il mappatore dei ruoli delle autorizzazioni esterne.
    conf_security_externalized.authentication.role.mapper.enabled=true conf_security_externalized.authentication.role.mapper.implementation.class=
    com.customer.authorization.impl.ExternalRoleMapperImpl

    Importante:
    la classe di implementazione e il nome del pacchetto a cui si fa riferimento nella configurazione precedente (ExternalRoleMapperImpl) siano solo degli esempi di cui si desidera implementare la classe (ExternalRoleMapperImpl). Per maggiori dettagli sull'implementazione di questa classe, consulta la sezione Informazioni sulla classe di implementazione di esempio di ExternalRoleMapperImpl di seguito. Questa è una classe che devi implementare per riflettere i tuoi gruppi.
  5. Salva il file management-server.properties.
  6. Assicurati che management-server.properties sia di proprietà dell'utente Apigee:?
    > chown apigee:apigee /opt/apigee/customer/application/management-server.properties
  7. Avvia il server di gestione:
    > /opt/apigee/apigee-service/bin/apigee-service edge-management-server start

Disabilitazione dell'autorizzazione esterna

Per disabilitare l'autorizzazione esterna:

  1. Apri /opt/apigee/customer/application/management-server.properties in un editor di testo. Se il file non esiste, crealo.
  2. Cambia l'archivio utenti di autenticazione in ldap:
    conf_security_authentication.user.store=ldap
  3. Imposta questa proprietà su false:
    conf_security_externalized.authentication.role.mapper.enabled=false
  4. Riavvia il server di gestione:
    > /opt/apigee/apigee-service/bin/apigee-service edge-management-server start

Informazioni sull'implementazione di esempio di ExternalRoleMapperImpl

Nel file di configurazione security.properties descritto in precedenza in Abilitazione della mappatura dei ruoli esterni, tieni presente quanto segue:

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

Questa classe implementa l'interfaccia ExternalRoleMapperServiceV2 ed è obbligatoria. Devi creare un'implementazione personalizzata di questo corso, che rifletta i tuoi rispettivi gruppi. Al termine, inserisci la classe compilata in un JAR e inseriscilo nel percorso della classe del server di gestione in:

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

Puoi assegnare un nome alla classe e al pacchetto come preferisci, purché implementi ExternalRoleMapperServiceV2, sia accessibile nel tuo classpath e venga indicato correttamente nel file di configurazione management-server.properties.

Di seguito è riportato un esempio di implementazione ben commentata di una classe 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();
   }

}