Mappage de rôle externe

Edge for Private Cloud v4.18.01

Le mappage de rôles externes vous permet de mapper vos propres groupes ou rôles à des rôles de contrôle des accès basés sur les rôles et à des groupes créés sur Apigee Edge. Cette fonctionnalité n'est disponible qu'avec le cloud privé Edge.

Nouveautés

Le service de mappage des rôles externes pour les versions de Edge for Private Cloud antérieures à la version 4.18.01 est obsolète. La version 4.18.01 du mappage de rôles externes est une version mise à jour avec des corrections de bugs et de nouvelles fonctionnalités:

  • Correction du problème qui entraînait la réception de réponses d'authentification 403 interdites lors de l'authentification avec des utilisateurs qui auraient dû y accéder.
  • X-Apigee-Current-User est désormais compatible avec le mappage des rôles externes. Les utilisateurs disposant d'un accès approprié (administrateur système) peuvent désormais afficher les rôles attribués à un autre utilisateur.

Conditions préalables

  • Pour effectuer cette configuration, vous devez être un administrateur système du cloud privé Apigee avec des identifiants d'administrateur système global.
  • Vous devez connaître le répertoire racine de votre installation de cloud privé Apigee Edge. Le répertoire racine par défaut est /opt.

Exemple de configuration étape par étape

Consultez cet article sur les forums de la communauté Apigee pour obtenir un exemple détaillé de configuration du mappage de rôles externes.

Configuration par défaut

Le mappage des rôles externes est désactivé par défaut.

Activer le mappage des rôles externes

  1. Avant de pouvoir effectuer la configuration suivante, vous devez créer une classe Java qui implémente l'interface ExternalRoleMapperServiceV2 et inclure votre implémentation dans le classpath de Management Server:

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

    Pour en savoir plus sur cette implémentation, consultez la section À propos de l'exemple d'implémentation ExternalRoleMapperImpl plus loin dans ce document.
  2. Connectez-vous à votre serveur de gestion Apigee Edge, puis arrêtez le processus du serveur de gestion:
    > /opt/apigee/apigee-service/bin/apigee-service Edge-management-server stop
  3. Ouvrez /opt/apigee/customer/application/management-server.properties dans un éditeur de texte. Si ce fichier n'existe pas, créez-le.
  4. Modifiez le fichier de propriétés pour définir les paramètres suivants:
    # Store de l'utilisateur à utiliser pour l'authentification.
    # Utilisez "externalized.authentication" pour le magasin d'utilisateurs LDAP.
    # Notez que nous continuons d'utiliser LDAP pour l'autorisation.
    # Pour en savoir plus sur l'activation de l'authentification externe, consultez Activer l'authentification externe.
    conf_security_authentication.user.store=externalized.authentication

    #Activez le mappeur de rôles externe pour les autorisations.
    conf_security_externalized.authentication.role.mapper.enabled=true conf_security_externalized.authentication.role.mapper.implementation.class=
    com.customer.authorization.impl.ExternalRoleMapperImpl

    Important:
    La classe d'implémentation et le nom de package référencés dans la configuration ci-dessus ne sont que des exemples de classe dont vous souhaitez implémenter (ExternalRoleMapperImpl, ou autre classe dont vous souhaitez implémenter la classe). Vous ne pouvez utiliser que des exemples de classe dont vous souhaitez implémenter la classe (ExternalRoleMapperImpl). Pour en savoir plus sur la mise en œuvre de cette classe, consultez la section À propos de l'exemple d'implémentation d'ExternalRoleMapperImpl ci-dessous. Il s'agit d'une classe que vous devez implémenter pour refléter vos propres groupes.
  5. Enregistrez le fichier management-server.properties.
  6. Assurez-vous que management-server.properties appartient à l'utilisateur Apigee :
    > chown apigee:apigee /opt/apigee/customer/application/management-server.properties
  7. Démarrez le serveur de gestion:
    > /opt/apigee/apigee-service/bin/apigee-service Edge-management-server start

Désactivation de l'autorisation externe

Pour désactiver l'autorisation externe:

  1. Ouvrez /opt/apigee/customer/application/management-server.properties dans un éditeur de texte. Si le fichier n'existe pas, créez-le.
  2. Remplacez le magasin des utilisateurs d'authentification par ldap:
    conf_security_authentication.user.store=ldap
  3. Définissez cette propriété sur "false" :
    conf_security_externalized.authentication.role.mapper.enabled=false
  4. Redémarrez le serveur de gestion:
    > /opt/apigee/apigee-service/bin/apigee-service Edge-management-server start

À propos de l'exemple d'implémentation d'ExternalRoleMapperImpl

Dans le fichier de configuration security.properties décrit précédemment dans la section Activer le mappage de rôles externe, notez la ligne suivante:

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

Cette classe est obligatoire et implémente l'interface ExternalRoleMapperServiceV2. Vous devez créer votre propre implémentation de cette classe, qui reflète vos groupes respectifs. Une fois l'opération terminée, placez la classe compilée dans un fichier JAR et placez ce fichier dans le classpath du serveur de gestion à l'emplacement suivant:

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

Vous pouvez nommer la classe et le package comme vous le souhaitez, à condition qu'il mette en œuvre ExternalRoleMapperServiceV2, qu'il soit accessible dans votre classpath et qu'il soit correctement référencé dans le fichier de configuration management-server.properties.

Vous trouverez ci-dessous un exemple d'implémentation bien commentée d'une 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();
   }

}